Looking for a clear tutorial on the revised NSPers

2019-03-11 08:45发布

问题:

I've reviewed Apple's:

Xcode 8 Release notes:
https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html

Migrating to Swift 2.3 or Swift 3 from Swift 2.2
https://swift.org/migration-guide/

What's New in Core Data in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0
https://developer.apple.com/library/content/releasenotes/General/WhatNewCoreData2016/ReleaseNotes.html#//apple_ref/doc/uid/TP40017342-CH1-DontLinkElementID_1

And many others... but the one document that should be available from Apple, the Core Data Programming Guide, hasn't been updated from Swift 2.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/FetchingObjects.html#//apple_ref/doc/uid/TP40001075-CH6-SW1

Ideally I'm looking for something like this but for Swift 3.
https://www.raywenderlich.com/115695/getting-started-with-core-data-tutorial

Any leads would be very much appreciated.

Per Tom's comment (below) What step am I missing?

1) Create a new project "Test"

2) Select use CoreDate (This creates Test.xcdatamodeld)

This will auto populate AppDelegate with the following (default comments removed):

func applicationWillTerminate(_ application: UIApplication) {
self.saveContext()
}
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "Test")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
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)")
        }
    }
}

3) Create entity "Foo"

4) Add Attribute "bar" type String

5) Under ViewController.swift add the following (This was copied from Apple, I just replaced "...use" with "print")

func findAnimals() {
    let request: NSFetchRequest<Foo> = Foo.fetchRequest
    do {
        let searchResults = try context.fetch(request)
        print(searchResults)
    } catch {
        print("Error with request: \(error)")
    }
}

6) Add findAnimals() under override func viewDidLoad().

However this has errors specifically:

  1. NSFetchRequest < Use of undeclared type 'NSFetchRequest'
  2. context < Use of unresolved identifier 'context'

7) So you go back and add something this to the function under the viewController to make the container accessible (which wasn't in the example form Apple).

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

Great we cleared 1 of the 2 error but the error " Use of undeclared type 'NSFetchRequest' " remains.

And here is where I'm stuck. Even after reviewing all of Apple's published materials I am unable to find a complete example.

回答1:

@Aaron Thanks again for the video link, that got me on the right track. Below is quick walk through for the bare minimum needed to fetch, add, and clear from core data with Swift 3 in Xcode 8.

  1. New project > iOS Single view application
  2. Product Name: "Sample"
  3. Use Core Data (checked)
  4. Save
  5. Open Sample.xcdatamodeld
  6. Add and entity: "SampleEntity"
  7. Use the Data Model inspector to set Codegen (under Class) to "Class Definition"
  8. Create an attribute under the new entity: "sampleAttribute"
  9. Open ViewController.swift
  10. Under "import UIKit" add "import CoreData"
  11. Under Class ViewController add the following:

    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    // Get data from he attribute
    func getSample() {
        let request: NSFetchRequest = SampleEntity.fetchRequest()
        request.resultType = NSFetchRequestResultType.dictionaryResultType
        do {
            let searchResults = try context.fetch(request as! NSFetchRequest<NSFetchRequestResult>) as! [NSDictionary]
            let searchResultsArray = searchResults.map { $0["sampleAttribute"] as! String}
            print("searchResultsArray", searchResultsArray)
        } catch {
            print("Error with request: \(error)")
        }
    }
    
    // Save to the attribute
    func setSample() {
        let saveSample = SampleEntity(context: context)
        saveSample.sampleAttribute = "Save a new string."
        do {
            try context.save()
        } catch {
             print("Error with save: \(error)")
        }
    }
    
    // clear the attribute
    func resetSample() {
        let clearSample: NSFetchRequest = SampleEntity.fetchRequest()
        let deleteResults = NSBatchDeleteRequest(fetchRequest: clearSample as! NSFetchRequest<NSFetchRequestResult>)
        do {
            try context.execute(deleteResults)
            try context.save()
        } catch {
            print("Error with save: \(error)")
        }
    }
  12. Under override func viewDidLoad() add the following:

    getSample()
    setSample()
    getSample()
    resetSample()
    getSample()
  13. Run and you will see the following printed in the debugging area:

    searchResultsArray []                       // Initially the attribute is empty
    searchResultsArray ["Save new string."]     // The attribute now contains the string 
    searchResultsArray []                       // This attribute has been cleared


回答2:

May be the video of this years WWDC What's New in Core Data can give you some more inside.

At approximately minute 31:20 he is showing some code regarding NSFetchRequest.



回答3:

From my understanding, NSPersistentContainer decouples main context and worker context in a simple way. One can simply call container.viewContext for any UI level data access (old NSMainQueueConcurrencyType), and use container.newBackgroundContext for other data import work (old NSPrivtaeQueueConcurrencyType). And by setting automaticallyMergesChangesFromParent to true to any context, it equals to old listening to NSManagedObjectContextDidSaveNotification.

Reference: http://holko.pl/2016/06/23/core-data/



回答4:

I still cannot leave comments. So let me put it here. I believe these two videos will help you a lot. Great Stanford Courses by Paul Hegarty are up to date!

https://www.youtube.com/watch?v=ssIpdu73p7A - lecture about CoreData https://www.youtube.com/watch?v=whF63GTaW1w - demo for using CoreData.