2016-12-01 73 views
2

在将我的应用程序升级到Swift 3和iOS 10之前,我没有将CoreData用作简单对象的数据存储的问题。轻量级迁移非常简单,节省成本,提取简单等。但自从最近的升级以来,我一直在CoreData遇到麻烦。Swift 3/iOS 10,正确的核心数据使用

我的问题分两部分。首先,是否有人知道有哪些好的资源可以帮助我了解CoreData如何在幕后工作,以便我能够更好地进行调试? Apple的文档极其有限,我阅读的所有文章都像新的CoreData一样简单。我有关于关系数据库的体面经验,所以CoreData为我添加了一个不舒服的抽象层。

二,以下代码有什么问题?使用此代码轻量级迁移不像iOS 10之前那样工作。对象保存到CoreData(我可以在保存后在应用程序中与它们交互),但在应用程序重新启动后消失。

lazy var persistentContainer: NSPersistentContainer = { 

    let description = NSPersistentStoreDescription() 

    description.shouldInferMappingModelAutomatically = true 
    description.shouldMigrateStoreAutomatically = true 

    let container = NSPersistentContainer(name: "MY_APP") 
    container.persistentStoreDescriptions = [description] 
    let description = NSPersistentStoreDescription() 

    description.shouldInferMappingModelAutomatically = true 
    description.shouldMigrateStoreAutomatically = true 

    container.persistentStoreDescriptions = [description] 
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
     if let error = error as NSError? { 
      fatalError("Unresolved error \(error), \(error.userInfo)") 
     } 
    }) 
    return container 
}() 

// MARK: - Core Data Saving support 

func saveContext() { 
    let context = persistentContainer.viewContext 
    if context.hasChanges { 
     do { 
      try context.save() 
     } catch { 
      let nserror = error as NSError 
      fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 
     } 
    } 
} 

我使用一个单独的文件,以抽象我的对象存储:

class Repository 
{ 


func getContext() -> NSManagedObjectContext 
{ 
    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    return appDelegate.persistentContainer.viewContext 
} 


func delete<T>(_ a: some T) 
{ 

    getContext().delete(a as! NSManagedObject) 

} 


// ----------- Password Repo ---------- 


func savePassword(name: String, hint: String, un: String) { 
    let context = getContext() 

    //retrieve the entity that we just created 
    let entity = NSEntityDescription.entity(forEntityName: "Password", in: context) 

    let transc = NSManagedObject(entity: entity!, insertInto: context) 

    //set the entity values 
    transc.setValue(name, forKey: "name") 
    transc.setValue(hint, forKey: "thing") 
    transc.setValue(un, forKey: "newThing") 


    //save the object 
    do { 
     try context.save() 
    } catch let error as NSError { 
     print("Could not save \(error), \(error.userInfo)") 
    } catch { 

    } 
} 


func updatePassword(pas: Password) -> Password 
{ 
    let context = getContext() 
    //  sec.is_new = false 

    // TODO, add updates 

    // Try updating the model in the DB 
    do { 
     try context.save() 
    } catch { 
     print(error) 

    } 

    return pas 
} 


func fetchPasswords() -> [Password] 
{ 

    let context = getContext() 
    //create a fetch request, telling it about the entity 
    let fetchRequest: NSFetchRequest<Password> = Password.fetchRequest() as! NSFetchRequest<Password> 
    let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) 
    fetchRequest.sortDescriptors = [sortDescriptor] 

    do { 
     //go get the results 
     let searchResults = try getContext().fetch(fetchRequest) 
     return searchResults 

    } catch { 
     print("Error with request: \(error)") 
    } 

    return [] 
} 




// ----------- End Password Repo ---------- 





// ----------- Hints Repo ---------- 

func saveHint (name: String, hint: String) { 
    let context = getContext() 

    //retrieve the entity that we just created 
    let entity = NSEntityDescription.entity(forEntityName: "Hint", in: context) 

    let transc = NSManagedObject(entity: entity!, insertInto: context) 

    //set the entity values 
    transc.setValue(value1, forKey: "some_string") 
    transc.setValue(value2, forKey: "some_thing") 

    //save the object 
    do { 
     try context.save() 
    } catch let error as NSError { 
     print("Could not save \(error), \(error.userInfo)") 
    } catch { 

    } 
} 




func fetchHints() -> [Hint] 
{ 

    let context = getContext() 
    //create a fetch request, telling it about the entity 
    let fetchRequest: NSFetchRequest<Hint> = Hint.fetchRequest() as! NSFetchRequest<Hint> 
    let sortDescriptor = NSSortDescriptor(key: "my_key", ascending: true) 
    fetchRequest.sortDescriptors = [sortDescriptor] 

    do { 
     //go get the results 
     let searchResults = try getContext().fetch(fetchRequest) 
     return searchResults 

    } catch { 
     print("Error with request: \(error)") 
    } 

    return [] 
} 

} 

然后我把这个资源库类,像这样:

Repository().savePassword(name: nameText.text!, hint: hintSoFarLabel.text!, un: "Hey") 

repository类工作,直到我重新启动应用程序...

我也试图迁移到我的Core Da的新版本ta模型,它简单地添加了非可选的String属性(具有默认值),这将是iOS 9/Swift 2中的一个简单轻量级迁移。我错过了关于swift 3轻量级迁移的内容?

我毫不怀疑,问题是我没有足够好地理解iOS 10中的CoreData。我一直是一名软件工程师,但我只用iOS和Swift工作了几个月,所以请温和。并且预先感谢!

+0

如果事情变得更简单,'NSPersistentContainer'不是Swift 3的东西,也不是必需的。您可以继续使用与iOS早期版本相同的类。他们仍然工作,不被弃用。而且,消失的物体与迁移无关。如果迁移现有的持久性存储失败,则该应用在启动时会崩溃。 –

+0

@TomHarrington。谢谢,这是一个很好的建议,我会尝试一下。然而,这个特定的应用程序开始于Xcode 8,Swift 3和iOS 10目标。所以我想我应该坚持这些范例。我想弄清楚如何使用这样的应用程序进行简单的轻量级迁移。我在iOS 9之前编写了一个不同的应用程序,这就是我对iOS9迁移和iOS10的了解。 – Griffin

+0

我正在研究一个简单的应用程序和新的Coredata(swift3),我注意到每个人我都设置ShouldInferMapping ...和ShouldMigrateStoreAu ...为true来描述,并将它们设置为container.persistenStoreDescriptions,正如Griffin指出的那样,我的数据不会没有坚持。但是当我评论这些行时(将两个属性设置为true),我的所有数据都会返回(持续存在)。任何想法 ? – Ohmy

回答

1

嗯,我觉得自己像一个白痴。我添加了一个非可选字符串,并没有给它一个默认值。我总是把默认值赋给非字符串类型,但是Xcode的设置方式使得它看起来只是给了字符串默认值“”,如果没有其他的话。

将默认值添加到新属性允许迁移在Swift3/iOS10中工作。 Noob错误,但也许它会在未来帮助别人。