核心数据是否默认使用线程?

时间:2016-03-12 14:34:23

标签: ios swift core-data swift2

我在考虑使用coreData存储用户名和密码以保持用户的持久性。测试时我注意到,当我快速关闭程序后,保存数据并重新启动它以检查数据是否持久存在,有时会说没有任何东西,然后当我再次重新启动应用程序时,它就会存在。我等待的时间越长,重新启动应用程序的可能性就越大。

我正在将coreData添加到现有项目中,因此我创建了一个名为DataController.swift的控制器,并从apple复制了建议的代码。该代码如下。

import UIKit
import CoreData

class DataController: NSObject {
    var managedObjectContext: NSManagedObjectContext
    override init() {
        // This resource is the same name as your xcdatamodeld contained in your project.
        guard let modelURL = NSBundle.mainBundle().URLForResource("AppSettings", withExtension:"momd") else {
            fatalError("Error loading model from bundle")
        }
        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
        guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
            fatalError("Error initializing mom from: \(modelURL)")
        }
        let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
        self.managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        self.managedObjectContext.persistentStoreCoordinator = psc
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
            let docURL = urls[urls.endIndex-1]
            /* The directory the application uses to store the Core Data store file.
            This code uses a file named "DataModel.sqlite" in the application's documents directory.
            */
            let storeURL = docURL.URLByAppendingPathComponent("AppSettings.sqlite")
            do {
                try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
            } catch {
                fatalError("Error migrating store: \(error)")
            }
        }
    }
}

我的LoginViewController.swift如下:

import UIKit
import CoreData

class LoginViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!

let moc = DataController().managedObjectContext

@IBAction func SignUpButtonPressed(sender: UIButton) {
    print("sign up")
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

func textFieldShouldEndEditing(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}


override func viewDidLoad() {
    super.viewDidLoad()

    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
    view.addGestureRecognizer(tap)

    print("view loaded, check if already signed in here")

    let loggedIn = checkIfLoggedInAlready() //checks database to see

    if(loggedIn){
        print("was logged in!")
    }
}

func checkIfLoggedInAlready() -> Bool{
    let fetchRequest = NSFetchRequest(entityName: "AppSettings")
    //let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) //Deletes ALL appsettings entities

    do {

        let fetchRequest = try moc.executeFetchRequest(fetchRequest) as! [AppSettings]

        guard let appSettingsArrayItem = fetchRequest.first where fetchRequest.count>0 else {
            print ("no entities found...")
            return false
        }

        guard let username = (appSettingsArrayItem as AppSettings).username else{
            print ("username not found")
            return false
        }

        print("number Of AppSetting Entities =\(fetchRequest.count)")
        print(username)

        //The following code deletes ALL the entities!
        //try moc.persistentStoreCoordinator!.executeRequest(deleteRequest, withContext: moc)

        //To delete just '1' entry use the code below.

        //moc.deleteObject(appSettingsArrayItem)
       // try moc.save()//save deletion change.

        print("deleted particular entity item")

        return true
    } catch{
        fatalError("bad things happened \(error)")
    }


}

func dismissKeyboard() {
    //Causes the view (or one of its embedded text fields) to resign the first responder status.
    view.endEditing(true)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    print("prepar seque")
}

func displayErrorMessage(errorMessage: String){
    print("show error console with Error:"+errorMessage)
    let alert = UIAlertController(title: "Error", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alert, animated: true, completion: nil)
}

override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
    switch(identifier){
        case "loginSegue":

            print("loginSegue Check")

            guard let password = passwordField.text!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()) where !password.isEmpty else {
                displayErrorMessage("Password can not be empty!")
                return false
            }

            guard let username = usernameField.text!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()) where !username.isEmpty else{
                displayErrorMessage("Username can not be empty!")
                return false
            }

            let url = "http://mywebsite.com/restapi/v1/userlogin?email="+username+"&password="+password
            print(url)

            let json = JSON(url:url)
            print(json)

            if(json["status"].asInt==1){

                let entity = NSEntityDescription.insertNewObjectForEntityForName("AppSettings", inManagedObjectContext: moc) as! AppSettings

                entity.setValue(username, forKey: "username")
                entity.setValue(password, forKey: "password")
                entity.setValue(json["tokenid"].asString, forKey: "token")
                entity.setValue(json["roleid"].asInt, forKey: "roleid")
                entity.setValue(json["role"].asString, forKey: "role")
                entity.setValue(json["companyid"].asInt , forKey: "companyid")
                entity.setValue(json["isdev"].asInt, forKey: "isdev")

                //save token and other details to database.
                do {
                    try moc.save()
                    print("saved to entity")
                }catch{
                    fatalError("Failure to save context: \(error)")
                }

                //token
                //roleid int
                //role
                //companyid int



                return true //login succesfull
            }else{
                displayErrorMessage("Incorrect Username or Email")
                return false//failed
            }

    default:
        displayErrorMessage("Unknown Error Related To Segue Not Found")
    }
  return false //if it gets to this point assume false
}
}

要测试我的代码,您只需取消注释删除函数checkIfLoggedInAlready()中删除实体(//moc.deleteObject(appSettingsArrayItem) )的部分。

简而言之,虽然这个问题的答案是简单的是或否,但我有预感其线程,这就是为什么延迟很重要。我认为它的线程是因为DataController.swift中的这一行

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0))

但不确定这是否会影响它。创建实体的代码在LoginViewController.swift的shouldPerformSegueWithIdentifier中完成

1 个答案:

答案 0 :(得分:3)

默认不是。所有NSManagedObject都绑定到具有它自己队列的NSManagedContext。如果需要并发,则需要使用专用队列创建另一个NSManagedContext。您可以在此处阅读Core Data中的并发性:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Concurrency.html

此外,永远不要将dispatch_async用于核心数据。每个上下文都有自己的peformBlock在其队列中运行。