簡體   English   中英

CoreData阻止UI

[英]CoreData blocking UI

我正在使用CoreData進行現有項目:

從Web服務接收到許多來自不同CoreData實體類型的項目后,這些項目會被阻塞,即使我在另一個線程中使用它,也會阻塞UI線程很多秒鍾。

請幫助我,有什么方法可以防止CoreData在項目即將完成時以最少的更改阻止UI?

我是CoreData ,但是我沒有足夠的時間研究文檔或重新編程源代碼。

我的DataController:

class DataController {

var managedObjectContext: NSManagedObjectContext
let modelName = "something"


init(closure:()->()) {

    guard let modelURL = NSBundle.mainBundle().URLForResource(modelName, withExtension: "momd"),
        let managedObjectModel = NSManagedObjectModel.init(contentsOfURL: modelURL)
        else {
            fatalError("DataController - COULD NOT INIT MANAGED OBJECT MODEL")
    }

    let coordinator = NSPersistentStoreCoordinator.init(managedObjectModel: managedObjectModel)

    managedObjectContext = {
        let parentContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
        parentContext.persistentStoreCoordinator = coordinator

        let managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        managedObjectContext.parentContext = parentContext
        return managedObjectContext
    }()

    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)) {

        let options = [
            NSMigratePersistentStoresAutomaticallyOption: true,
            NSInferMappingModelAutomaticallyOption: true,
            NSSQLitePragmasOption: ["journal_mode": "DELETE"]
        ]

        let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last
        let storeURL = NSURL.init(string: "something", relativeToURL: documentsURL)


        do {
            try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options)

            dispatch_async(dispatch_get_main_queue()) {
                closure()
            }
        }
        catch let error as NSError {
            fatalError("DataController - COULD NOT INIT SQLITE STORE: \(error.localizedDescription)")
        }
    }
}

func save(moc: NSManagedObjectContext? = nil) {

    var managedObjectContext = moc

    if moc == nil {
        managedObjectContext = self.managedObjectContext
    }

    managedObjectContext!.performBlockAndWait {

        if managedObjectContext!.hasChanges {

            do {
                try managedObjectContext!.save()
            } catch {
                print("ERROR saving context \(managedObjectContext!.description) - \(error)")
            }
        }

        if let parentContext = managedObjectContext!.parentContext {
            self.save(parentContext)
        }
    }
}


}

我的課是這樣的:

class MOCity: NSManagedObject {

@NSManaged var id: NSNumber?
@NSManaged var name: String?

// Insert code here to add functionality to your managed object subclass
class func save(id: NSNumber, json: JSON, managedObjectContext: NSManagedObjectContext) {

    guard let newObject = MOCity.getById(id, create: true, managedObjectContext: managedObjectContext) else {
        fatalError("City - NO OBJECT")
    }

    newObject.id                <-- json["Id"]
    newObject.name              <-- json["Name"]

}

internal class func getById(id: NSNumber, create: Bool = false, managedObjectContext: NSManagedObjectContext) -> MOCity? {

    let fetchRequest = NSFetchRequest(entityName: "City")
    fetchRequest.predicate = NSPredicate(format: "id = \(id)")

    do {
        guard let fetchResults = try managedObjectContext.executeFetchRequest(fetchRequest) as? [MOCity] else {
            fatalError("city - NO FETCH RESULTS")
        }

        if fetchResults.count > 0 {
            return fetchResults.last
        }
        else if fetchResults.count == 0 {

            if create {
                guard let object = NSEntityDescription.insertNewObjectForEntityForName("City", inManagedObjectContext: managedObjectContext) as? MOCity else {
                    fatalError("getCity - COULD NOT CREATE OBJECT")
                }
                return object
            } else {
                return nil
            }
        }
    }
    catch let error as NSError {
    ...
    }

    return nil
}
}

和我的網絡服務類:

Alamofire.request(.POST, url,parameters:data).validate().responseJSON(completionHandler: {response in

        switch response.result {

        case .Success:

            if let jsonData = response.result.value {

                if let array = jsonData as? NSArray {

                for arrayItem in array {
                    MOCity.save(arrayItem["Id"] as! NSNumber, json: JSON(arrayItem as! NSDictionary)!, managedObjectContext: self.dataController.managedObjectContext)
                }

                self.dataController.save()

                }

            }
            break
        case .Failure(let error):
        ...                
        }


    })

問題之一可能與QOS級別有關。

QOS_CLASS_USER_INITIATED:用戶啟動的類表示從UI啟動並可以異步執行的任務。 當用戶等待即時結果以及繼續用戶交互所需的任務時,應使用它。

嘗試使用QOS_CLASS_BACKGROUND

我建議兩件事。 首先,就像處理主隊列上下文一樣,將私有隊列上下文保存在performBlock函數中。 其次,在不同的位置(例如保存前后)設置斷點,以檢查哪個線程正在調用該代碼(使用NSThread的線程檢查方法)。 這可能會啟發您從哪個線程執行什么代碼。 希望能幫助您指引正確的方向。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM