How to define entity identity - cocoa-touch

Is there a way to define which attributes of an entity should define its objects' NSManagedObjectID?
Rather than having to build extra dictionaries and loops to compare them by property values, I'd like to be able to just use -[NSManagedObjects isEqual:] directly, and the NSSet functionality that would also allow.
Put another way: if an entity has an attribute that would logically be its primary key, how to tell CoreData to use it as such for object equality tests?

You don't. And subclassing wouldn't help anyway.
Core Data doesn't care if you create duplicate records. As far as it's concerned, two managed objects are equal if they represent the same underlying instance in the persistent store. It has no other concept of "equal" between managed objects.
Subclassing doesn't help because, as the docs for NSManagedObject explain:
NSManagedObject itself customizes many features of NSObject so that managed objects can be properly integrated into the Core Data infrastructure. Core Data relies on NSManagedObject’s implementation of the following methods, which you therefore absolutely must not override: [...] isEqual:,
You can create your own methods for comparing managed objects any way you like, but any behavior that relies on isEqual: is going to get Core Data's standard behavior.

Related

What is best approach? NSDictionary Or Custom Object based Data strcuture?

I was talking to several developers which approach is best in objective C according to latest trends?
For example: if i am populating data from server in json form, which approach should i use?
I have seen my friends populating data into json objects in past as well as fewer of them in NSdictiory,NSMututable Dictionary, what apple recommends data structure wise?
any help would be appreciated.
I personally greatly prefer custom objects (or Structs for Swift) because it lets me more easily tell what properties the objects have. If you are just passing around dictionaries it makes it much harder (in my opinion) to remember what object you have, what keys it has, and maybe what nested objects it has too. Whereas if you have named classes (again, these ought to be Structs in Swift), then you (and the compiler) can easily know what properties they have. Plus you can easily create instance methods for your objects.
And if you don't want the pain of parsing them yourself there are frameworks that will manage parsing the server response into objects (e.g. RestKit https://github.com/RestKit/RestKit).
If you consider example code from Apple as a "recommendation" from Apple, you can see the way they make a data model in their "Start Developing iOS Apps" here: https://developer.apple.com/library/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson6.html. Yes the example is for Swift but most concepts are comparable.
Apple also has "Cocoa Core Competencies" (https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/ModelObject.html) where they define a modal object as "typically a subclass of NSObject or...a subclass of NSManagedObject."

Correct way of dealing with Core Data NSManagedObjects in an iOS application

When I have worked with Java applications involving a database and ORM (object relationship manager) the architecture was usually separated so when working with database entities in the database layer you worked directly with the entities. But if you needed to access the entities in the GUI you would create a data transfer object (DTO) of the entity and then use it in the GUI layer.
What is the preferred approach in iOS applications?
One example would be that I do a fetch from Core Data to retrieve some objects in a ViewController and then display the results in a TableView in the ViewController. Is it necessary to convert the NSManagedObjects to DTOs before showing the results?
What is the preferred approach in iOS applications?
Is it necessary to convert the NSManagedObjects to DTOs before showing the results?
No, it is not neccessary. The managed object is already a (generic) object wrapping the database entity. You can access the managed object's properties (ie the entitys attributes) using -valueForKey: calls.
But the preferred approach is to subclass NSManagedObject to fit your entities. In Xcode there is an option to generate subclasses automatically (editor-> generate NSManagedObject subclass). That way you get your own subclass object for your entities and can access their properties using dot notation.
On fetching objects, just let the result be of type of that subclass.
If you want to add custom methods to your entity objects, you should create a category on your managed object subclass. This is because if you change your db scheme and have to let xcode recreate your subclasses, it completely overwrites the and your custom methods would be lost.

how to serialize polymorphic to-many Core Data relationship with RestKit?

I need to serialize a Core Data class (Questionnaire) which has a to-many relationship (questions) to an abstract entity (Question).
Question is the parent entity for a number of concrete subclasses (BooleanQuestion, ClosedQuestion…), each of which has an RKManagedObjectMapping.
How can I set up the Questionnaire mapping to serialize this polymorphic relationship?
If it was not polymorphic, I would do:
[questionnaireMapping mapRelationShip:#"questions" withMapping:[questionMapping inverseMapping]];
But I can't do that: questions will not be of any single class, so there isn't a single mapping to pass.
Moreover, Question being abstract, doesn't even have a mapping (though I could define one).
How can I handle that with RestKit version 0.10.3?
Note that I am very close to releasing my product, and I am really reluctant to migrate to RestKit 0.20 this late in my product cycle.
I guess I could aggregate all concrete Question subclasses into Question, making it concrete and monomorphic (and monolithic). That would be ugly (though I believe this is precisely what Core Data does with SQLite behind the scene).
Anything more elegant?
Thanks
JD
Upgrading to 0.20 wouldn't help anyway as I don't believe this situation is covered there either.
I would recommend you to implement a method (or just use KVC) on each of the classes in the hierarchy which returns a dictionary of the keys and values. This can be done efficiently using KVC -dictionaryWithValuesForKeys:. The list of keys should be the union of all keys for all classes. Now you can build an array of dictionaries which can be mapped. You would also need to implement KVC -valueForUndefinedKey: to prevent exceptions during this process.
Now, on your Questionnaire class you can implement a method to loop over the questions relation contents and build the list of dictionaries. Say the method was called encodedQuestions, your mapping would be something like:
[questionnaireMapping mapRelationShip:#"encodedQuestions" withMapping:questionDictMapping];
I haven't actually tried doing this so there is a question about the reflection RestKit uses on Core Data objects and how happy it will be taking your relation mapping.

Objective-C undo manager questions

I'm reading a book on Objective-c and learning about the undo manager. The concept seems very simple but the provided example seems overly complex. Basically, I have a table view connected to an NSArrayController and I add or remove people to an array and I can edit their names and stuff. Because the example uses NSArrayController and bindings, add and remove are automatic and all of the editing is automatic.
To use the undo manager, from what I understand, I need to implement my own methods to add/remove/edit.
These methods I've implemented to do the adding and removing and get called automatically due to key value coding:
- (void)removeObjectFromEmployeesAtIndex:(int)index;
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index;
Then for editing, I had to register the class as an observer and observe changes to edit:
- (void)changeKeyPath:(NSString *)keyPath
ofObject:(id)obj
toValue:(id)newValue
Here are my questions:
Why do I have to do so much? My understanding was that using the NSArrayController and bindings was supposed to make things like adding/removing/editing items easier and more automatic. But if I have to implement all of these methods manually anyway just to add undo support, why use NSArrayController or bindings at all?
What's going on behind the scenes? In Interface Builder, the add button is connected to the add method on the NSArrayController. How then does my insertObject method get called? I know it's through key value coding but what makes the NSArrayController's add method get overridden just b/c my document implements this method?
The solution is asymmetric. I use one concept to handle undoing add/remove and another concept to handle undoing edits. Couldn't I also just observe changes to the array? I suppose it would complicate the observeValueForKeyPath method, but would that make more sense?
1) Nearly, but not quite. If you think of your application code being divided into three overall areas: Model, View and Controller (as documented here) then the Cocoa/XCode environment provides you with a 'code-free' way of handling the basics of each: IB for the view, Core Data for the model, and Bindings / Object Controllers for the controller.
Undo management is primarily a concern of the model, not the view or controller. So it's not really Bindings or the Object controller's job to manage this stuff. It looks like your problem is that you're using arrays as your data objects, which are too lightweight to handle this stuff. If you want undo support, you'll want to use core data to handle the model and give you this stuff for free, or hand-roll your own model objects, (which will probably contain arrays) which handle this logic.
FWIW, once you've done this, bindings will indirectly make your life much easier, as when an undo command reverts your data to its previous state, the view will automatically reflect the changes.
Also, NSArrayController's name is slightly misleading -- it isn't there to 'control arrays'. It's really for controlling data objects which have to-many relationships to other data objects. Which brings me on to...
2) KVC allows you to treat a to-many relationship between an object and other objects as an array or set, regardless of how the relationship is actually implemented. It does so by requiring you to implement methods fitting a naming convention, which very closely match the primitive methods of arrays and sets. KVC-compliant objects will return a proxy array or set when you call mutableArrayValueForKey: or mutableSetValueForKey:, which exposes those methods as an array. Roughly, that's how NSArrayController knows what to call --- KVC maps between the primitive objects of an array and some methods whose manes it generates from the key. Since you don't want to use arrays as your data objects, it's generally very useful to be able to treat any to-many relationship as if it were just an ordinary collection.
3) I think this is related to you handling undo in the wrong place. Implement KVC-compliant methods to get/set properties in your data objects, have them update the undoManger at the same time as setting the data. You'll need a special method for the undomanager to revert changes, as you don't want undos to be recorded as undoable. Or you could just use Core Data and get all this stuff for free...

Core Data - Managed object question

I have 2 basic questions regarding Core Data;
What exactly is a managed object -- Is it equivalent to 1 instance of a class. For example, if there is an entity called Shape which has attributes like no of sides & color and if there are 5 entries displayed in a table, does it mean there are 5 managed objects each with attributes no. of sides & color. I am a bit confused about this basic concept.
What exactly is the relationship between Fetched Results Controller (FRC) and a table view? I know the delegate methods, but how exactly is the table view impacted/related to FRC ?
Any basic examples will be really useful. Thank you.
Q1. A managed object is a representation of some entity that has been persisted by an application. It is simply a generic abstraction away from the actual persisted type. So you are right in saying that the managed object will have the same keys/properties as the concrete type. As the NSManagedbject class implements the key-value coding pattern you can query its key/values at runtime...
- (id)valueForKey:(NSString *)key
For full documentation on NSManagedObject see here
Q2. The fetched results controller is what your UIViewController is to your UIView. It contains the logic that controls persistence for your table view. Its sole purpose in life is to keep database handling logic out of your UITableView. It does so by allowing you to define the behaviour you want to execute in the context of your UITableView. What I mean by this is that its delegate provides methods with signatures that explicitly imply an effect on a UITableView.
Q1. Yes, there are 5 managed objects out there and available to you. You could put all five in an array if you wanted to. Managed Object is simply a term that means you have code to manage the Insert, Change, and Delete actions into the database - in otherwords, some code manages it through its life cycle. You get at it through an FRC, the FRC ^fetches^ instances of the object from the database, and allows your code to ^control^ what happens to the ^result^. Hence the name.