Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for a clear tutorial on the revised NSPersistentContainer in Xcode 8 with Swift 3

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.

like image 757
Michael Garito Avatar asked Sep 20 '16 05:09

Michael Garito


2 Answers

@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
like image 101
Michael Garito Avatar answered Oct 02 '22 09:10

Michael Garito


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.

like image 25
Aaron Avatar answered Oct 02 '22 09:10

Aaron