Search code examples
iosswiftcore-datansmanagedobjectcontextnsfetchrequest

Fetching selected attribute in entities


I have a core-data entity with several attributes, and I want a list of all the objects in one attribute. My code looks like this:

        let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        let context:NSManagedObjectContext = appDel.managedObjectContext!

        let sortDesc = NSSortDescriptor(key: "username", ascending: true)

        let fetchReq = NSFetchRequest(entityName: "Identities")
        fetchReq.sortDescriptors = [sortDesc]
        fetchReq.valueForKey("username")

        let en = NSEntityDescription.entityForName("Identities", inManagedObjectContext: context)

        userList = context.executeFetchRequest(fetchReq, error: nil) as [Usernames]

But this gives me an NSException-error, and I can't figure out why, or how I'm supposed to do this. I've read the NSFetchRequest class description but couldn't make much sense out of it.

Any suggestions would be appreciated.

EDIT: After a tip from Bluehound I changed my code to this:

var userList = [Model]()
@IBAction func printUsers(sender: AnyObject) {
    let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let context:NSManagedObjectContext = appDel.managedObjectContext!

    let sortDesc = NSSortDescriptor(key: "friendID", ascending: true)

    let fetchReq = NSFetchRequest(entityName: "Identities")
    fetchReq.sortDescriptors = [sortDesc]
    fetchReq.propertiesToFetch = ["friendID"]

    let en = NSEntityDescription.entityForName("Identities", inManagedObjectContext: context)

    userList = context.executeFetchRequest(fetchReq, error: nil) as [Model]

    println(userList)

}

The runtime error is gone but I still don't know if it works because I'm not sure how to convert the list to a list of strings.

As always, suggestions would be appreciated.


Solution

  • There are two possibilities: You can issue a normal fetch request and extract an array containing the wanted attribute from the result, using map():

    let fetchReq = NSFetchRequest(entityName: "Identities")
    fetchReq.sortDescriptors = [sortDesc]
    
    var error : NSError?
    if let result = context.executeFetchRequest(fetchReq, error: &error) as? [Model] {
        let friendIDs = map(result) { $0.friendID }
        println(friendIDs)
    } else {
        println("fetch failed: \(error!.localizedDescription)")
    }
    

    Swift 2:

    let fetchReq = NSFetchRequest(entityName: "Identities")
    fetchReq.sortDescriptors = [sortDesc]
    
    do {
        let result = try context.executeFetchRequest(fetchReq) as! [Model]
        let friendIDs = result.map { $0.friendID }
        print(friendIDs)
    } catch let error as NSError {
        print("fetch failed: \(error.localizedDescription)")
    }
    

    Or you set the resultType to .DictionaryResultType and propertiesToFetch to the wanted attribute. In this case the fetch request will return an array of dictionaries:

    let fetchReq = NSFetchRequest(entityName: "Identities")
    fetchReq.sortDescriptors = [sortDesc]
    fetchReq.propertiesToFetch = ["friendID"]
    fetchReq.resultType = .DictionaryResultType
    
    var error : NSError?
    if let result = context.executeFetchRequest(fetchReq, error: &error) as? [NSDictionary] {
        let friendIDs = map(result) { $0["friendID"] as String }
        println(friendIDs)
    } else {
        println("fetch failed: \(error!.localizedDescription)")
    }
    

    Swift 2:

    let fetchReq = NSFetchRequest(entityName: "Identities")
    fetchReq.sortDescriptors = [sortDesc]
    fetchReq.propertiesToFetch = ["friendID"]
    fetchReq.resultType = .DictionaryResultType
    
    do {
        let result = try context.executeFetchRequest(fetchReq) as! [NSDictionary]
        let friendIDs = result.map { $0["friendID"] as! String }
        print(friendIDs)
    } catch let error as NSError {
        print("fetch failed: \(error.localizedDescription)")
    }
    

    The second method has the advantage that only the specified properties are fetched from the database, not the entire managed objects.

    It has the disadvantage that the result does not include pending unsaved changes in the managed object context (includesPendingChanges: is implicitly set to false when using .DictionaryResultType).