2016-12-01 69 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錯誤,但也許它會在未來幫助別人。