Skip to content

Instantly share code, notes, and snippets.

Created January 12, 2017 12:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/0e5e60bffc677044ab84a1994be0e90d to your computer and use it in GitHub Desktop.
Save anonymous/0e5e60bffc677044ab84a1994be0e90d to your computer and use it in GitHub Desktop.
//
// DBRoot.swift
// italki
//
// Created by Hongli Yu on 12/10/2016.
// Copyright © 2016 italki. All rights reserved.
//
import Foundation
import RealmSwift
typealias ClosureType = () -> ()
final public class DBRoot {
var reamlTaskThread: Thread?
var queueCondition: NSCondition = NSCondition()
var blockQueue: Array = [ClosureType]()
var reamlTaskRunloop: CFRunLoop?
init() {
self.config()
self.createTaskThread()
}
func reset() {
self.config()
}
// MARK: Realm Task Thread
/// Remember that Realm objects can only be accessed from the thread on which they were first created, so this copy will only work for Realms on the same thread.
/// All db opration in datamanager concurrent queue, but in the same thread
func createTaskThread() {
if self.reamlTaskThread == nil {
self.reamlTaskThread = Thread(target: self,
selector: #selector(DBRoot.taskThreadEntryPoint(_:)),
object: nil)
self.reamlTaskThread!.start()
}
}
@objc func taskThreadEntryPoint(_ sender: AnyObject?) {
autoreleasepool {
Thread.current.name = "realm_task_thread"
self.reamlTaskRunloop = CFRunLoopGetCurrent()
let runloop: RunLoop = RunLoop.current
runloop.add(NSMachPort(), forMode: RunLoopMode.commonModes)
runloop.run()
}
}
@objc func realmTaskStart() {
self.queueCondition.lock()
var block: ClosureType?
if self.blockQueue.first != nil {
block = self.blockQueue.removeFirst()
#if DEBUG
//print(block)
#endif
}
self.queueCondition.unlock()
block?()
}
func enqueueRealmTask(_ block: @escaping ClosureType) {
self.queueCondition.lock()
self.blockQueue.append(block) // how to copy a block
self.queueCondition.unlock()
}
func addTask(_ block: @escaping ClosureType) {
self.enqueueRealmTask(block)
while true {
if self.reamlTaskRunloop == nil {
#if DEBUG
print("waiting run loop ready!")
#endif
} else {
break
}
}
weak var weakSelf = self
CFRunLoopPerformBlock(self.reamlTaskRunloop, CFRunLoopMode.commonModes.rawValue) {
let strongSelf = weakSelf
strongSelf?.realmTaskStart()
}
CFRunLoopWakeUp(self.reamlTaskRunloop)
}
// MARK: Realm Config
func config() {
let userName: String = UserCenter.defaultCenter.currentUser.nickname
if userName.isValid() {
self.setDefaultRealmForUser(userName)
}
}
func setDefaultRealmForUser(_ username: String) {
var config = Realm.Configuration()
config.schemaVersion = 1
config.migrationBlock = { migration, oldSchemaVersion -> Void in
migration.enumerateObjects(ofType: PackageDetail.className(), { (oldObject, newObject) in
// Add the `email` property to Realms with a schema version of 0
if oldSchemaVersion < 1 {
newObject!["packageMessageUnreadCount"] = 0
newObject!["packageMessageTotalCount"] = 0
}
})
}
let path = FileDirectoryManager.documentDirectory() + "/\(username).realm"
config.fileURL = URL(fileURLWithPath: path)
// Set this as the configuration used for the default Realm
Realm.Configuration.defaultConfiguration = config
}
// MARK: Database Actions
func insertPackages(_ packageViewModels: Array<PackageViewModel>?,
completion: @escaping (_ result: Bool, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
#if DEBUG
print(Realm.Configuration.defaultConfiguration.fileURL!)
#endif
do {
let realm = try Realm()
realm.beginWrite()
for packageViewModel in packageViewModels! {
let package: Package = packageViewModel.fetchPackage()
realm.add(package, update: true)
}
try realm.commitWrite()
completion(true, nil)
} catch let error as NSError {
completion(false , error)
}
}
}
self.addTask(block)
}
func insertPackageDetail(_ packageDetailViewModel: PackageDetailViewModel?,
completion: @escaping (_ result: Bool, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
do {
let realm = try Realm()
realm.beginWrite()
if packageDetailViewModel != nil {
let packageDetail: PackageDetail = packageDetailViewModel!.fetchPackageDetail()
realm.add(packageDetail, update: true)
}
try realm.commitWrite()
completion(true, nil)
} catch let error as NSError {
completion(false , error)
}
}
}
self.addTask(block)
}
func deletePackages(_ packageViewModels: Array<PackageViewModel>?,
completion: @escaping (_ result: Bool, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
do {
let realm = try Realm()
realm.beginWrite()
for packageViewModel in packageViewModels! {
let package: Package = packageViewModel.fetchPackage()
realm.delete(package)
}
try realm.commitWrite()
completion(true, nil)
} catch let error as NSError {
completion(false , error)
}
}
}
self.addTask(block)
}
func updatePackages(_ packageViewModels: Array<PackageViewModel>?,
completion: @escaping (_ result: Bool, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
do {
let realm = try Realm()
realm.beginWrite()
for packageViewModel in packageViewModels! {
let package: Package = packageViewModel.fetchPackage()
realm.add(package, update: true)
}
try realm.commitWrite()
completion(true, nil)
} catch let error as NSError {
completion(false , error)
}
}
}
self.addTask(block)
}
func selectPackages(_ completion: @escaping (_ result: Array<PackageViewModel>?, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
do {
var retArray: Array<PackageViewModel> = [PackageViewModel]()
let realm = try Realm()
realm.beginWrite()
let packages = realm.objects(Package.self).sorted(byProperty: "updateTime", ascending: false)
try realm.commitWrite()
if packages.count == 0 {
completion(nil, nil) // MARK: the table is empty, but no error
return
}
for package in packages {
let packageViewModel: PackageViewModel = PackageViewModel(package: package)
retArray.append(packageViewModel)
}
completion(retArray, nil)
} catch let error as NSError {
completion(nil , error)
}
}
}
self.addTask(block)
}
func selectPackageDetail(_ identifier: String,
completion: @escaping (_ result: PackageDetailViewModel?, _ error: NSError?)->()?) {
let block = {
autoreleasepool {
do {
let realm = try Realm()
realm.beginWrite()
let retArray = realm.objects(PackageDetail.self).filter("identifier == %@", identifier)
try realm.commitWrite()
if retArray.count == 0 {
completion(nil, nil) // MARK: the table is empty, but no error
return
}
let packageDetailViewModel: PackageDetailViewModel = PackageDetailViewModel(packageDetail: retArray.first)
completion(packageDetailViewModel, nil)
} catch let error as NSError {
completion(nil , error)
}
}
}
self.addTask(block)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment