1

I'm wondering how to essentially create the equivalent of a Category for my CoreData NSManagedObject Client below:

I understand that Extensions are now the replacement of Categories in Swift - however am unsure of their implementation. Here is what I have deducted below:

class Client: NSManagedObject {

    @NSManaged var name: String
    @NSManaged var projects: NSSet

}

extension Client {

    func addClientWithName(name:NSString, context:NSManagedObjectContext) -> Client {
        var client:Client = Client();

        // Check for name in the database already exists
        let request:NSFetchRequest = NSFetchRequest(entityName: "Client")
        let sortDescriptor:NSSortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        let sortDescriptorsAry:NSArray = [sortDescriptor]
        request.sortDescriptors = sortDescriptorsAry
        request.predicate = NSPredicate(format: "name = %@", name)

        var error:NSError?
        let matches:NSArray = context.executeFetchRequest(request, error: &error)

        if matches.count == 0 {

            //Add new Client
            var newClient:NSEntityDescription = NSEntityDescription.insertNewObjectForEntityForName("Client", inManagedObjectContext: context) as NSEntityDescription
            newClient.setValue(name, forKey: "name")

            context.save(nil);

        } else {
            client = matches.lastObject as Client
        }

        return client
    }
}

With this implementation however, this is the error i get so far:

CoreData: error: Failed to call designated initializer on NSManagedObject class "Ttc9AppName6Client"

Any ideas on what could be causing this?

Edit: This is how i call the method from my other class:

@IBAction func saveBtnTapped(UIButton) {
    println("save btn tapped")
    var client:Client = Client().addClientWithName("Woofy Face", context: self.managedObjectContext)
}
Tom Blodget
  • 18,829
  • 2
  • 35
  • 64
Ryan
  • 3,544
  • 7
  • 28
  • 52
  • Did you prefix the entities class name with the module name in the Core Data model inspector? Compare http://stackoverflow.com/a/25076929/1187415. – Martin R Aug 03 '14 at 17:09
  • @MartinR - i've double checked - Its definitely prefixed "AppName.Client" – Ryan Aug 03 '14 at 17:11

1 Answers1

6

I think your problem is unrelated to categories/extensions.

 var client:Client = Client();

does not call the designated initializer of NSManagedObject, and this object is returned if the fetch request found no matching object.

What you probably want is to return the newly created object in that case.

Note also that

insertNewObjectForEntityForName:inManagedObjectContext:

returns a managed object, not an entity description.

In addition,

var client:Client = Client().addClientWithName(...)

also creates a Client object without using the designated initializer. You should define the method as a class method instead.

So your code should look like this:

 class func addClientWithName(name:NSString, context:NSManagedObjectContext) -> Client {
    var client:Client

    let request:NSFetchRequest = NSFetchRequest(entityName: "Client")
    let sortDescriptor:NSSortDescriptor = NSSortDescriptor(key: "name", ascending: true)
    let sortDescriptorsAry:NSArray = [sortDescriptor]
    request.sortDescriptors = sortDescriptorsAry
    request.predicate = NSPredicate(format: "name = %@", name)

    var error:NSError?
    let matches:NSArray = context.executeFetchRequest(request, error: &error)

    if matches.count == 0 {
        //Add new Client
        client = NSEntityDescription.insertNewObjectForEntityForName("Client", inManagedObjectContext: context) as Client
        client.name = name
        context.save(nil)
    } else {
        client = matches.lastObject as Client
    }
    return client
}

and it would be called as

let client:Client = Client.addClientWithName("Woofy Face", context: self.managedObjectContext)
Martin R
  • 488,667
  • 78
  • 1,132
  • 1,248
  • Thanks: I see where you are coming from and have implemented your solution,- i still get however get: CoreData: error: Failed to call designated initializer on NSManagedObject class '_TtC9AppName6Client' – Ryan Aug 03 '14 at 17:29
  • Note that your function should be a *class function* : `class func addClientWithName ...` and should be called as `let cl1 = Client.addClientWithName(...)`. - I now tested that code and it seemed to work. – Martin R Aug 03 '14 at 17:45
  • I've just thrown into the IBAction and it works fine there, just not in the extension it seems – Ryan Aug 03 '14 at 17:49
  • this is a great solution, but i cant implement it because im moving the objects through a protocol. embedding a class function doesnt remove the error. any ideas? – Japes Sep 01 '15 at 08:25
  • @Japes: Sorry, but I don't get what you are asking. – Martin R Sep 05 '15 at 19:48
  • Thanks, but I found a solution. No worries. – Japes Sep 06 '15 at 02:10