I'm a little confused by whether Core Data generates primitive accessors for NSManagedObject subclasses in the form setPrimitiveAttributeName:, as compared to the form setPrimitiveValue: forKey:, which it seems to do consistently.
The source of my confusion is that I have used the modeling tool (XCode 4) to generate NSManagedSubclasses for two of my entities, which, as far as I can tell, share the same metadata settings, yet one subclass recognizes the setPrimitiveAttributeName form, whereas the other doesn't (it gives me a "method not found" compiler warning).
So, what is the expectation? If I open up a new project, create one entity with one attribute, and use the modeling tool to generate the necessary NSManagedObject subclass code, should I expect it to auto-generate the more efficient form of the primitive accessor or not?
I've been running into a similar problem. While the runtime generates the primitive accessors, Xcode 4 does not generate the declared properties for primitives, you have to do this yourself in the subclass, per the docs.
I personally create a category for every Entity and always put my custom code in there, that way I can regenerate the MOs whenever I want and not have to copy and paste.
You can do this in a category, the interface has this:
#property (nonatomic, retain) NSDate * primitiveLastUsed;
And the implementation has this:
#dynamic primitiveLastUsed;
Pretty slick, makes regenerating MOs from Xcode painless.
Related
I have an app that didn't start off using Core Data. Now I'm integrating Core Data.
I have a plain old class and that is used through out the app. So I can't get rid of it but also don't need to. It's properties do match the Core Data entity attribute names.
Is it necessary to inherit from NSManagedObject and supply #NSManaged to the properties of the class? What value does that add in this case?
One problem is that not all of the plain old class properties are exactly the same types as those in the Core Data Entity. So I have to a transformation when going from the class to Core Data and vice versa.
Is there some way for Core Data to do the transformation?
Is it necessary to inherit from NSManagedObject and supply #NSManaged to the properties of the class? What value does that add in this case?
Yes it is absolutely necessary because Core Data only works with instances of NSManagedObject or subclasses of NSManagedObject.
One problem is that not all of the plain old class properties are exactly the same types as those in the Core Data Entity. So I have to a transformation when going from the class to Core Data and vice versa.
If your properties are types that conform to NSCoding, you can make them Core Data "transformable" properties and it'll just work. If they aren't, the easiest option would be to try and add NSCoding conformance to the types. If that's not possible, you can create a custom subclass of NSValueTransformer and configure Core Data to use it for your property.
When you create a managed object relationship (i.e. one to many), and then you create a NSManagedObject subclass, you would code that relationship like:
#NSManaged var dogs: NSSet
But I found out that instead you can write:
#NSManaged var dogs: Set<Dog>
Which in my opinion, it is much more convenient because you have a typed Set and casting in Swift is quite verbose.
Edited:
Actually, I have found out that you can use the insert and remove method of the Set so it's even easier.
I know about Swift automatic bridging from some Foundation classes to Swift classes (i.e. NSArray to Array and NSSet to Set).
But I haven't found about using Swift typed Sets for implementing Core Data Managed object subclasses in the docs or in any other tutorial and I wonder why.
I'm using Xcode 7.2 and Swift 2 and it works fine in my project. Does it also work for someone else? some Apple doc somewhere? or is it a bad idea for some reason I'm missing?
Yes, this is common practice among many developers as far as I know.
In fact, the generated NSManagedObject subclasses are not at all perfect when it comes to the generated types. For examples, primitives still have problems, and NSNumber sometimes bridges successfully to Bool, sometimes not. Quite often I had to modify the optional state as well.
If you leave the preset NSSet, you can still cast to Set<Type> which is what I did before getting into the habit of changing the generated subclasses' to-many properties to typed sets.
From Apple's Core Data Programming Guide:
Core Data dynamically generates efficient public and primitive get and
set attribute accessor methods and relationship accessor methods for
managed object classes.
...
Primitive accessor methods are similar to "normal" or public key-value
coding compliant accessor methods, except that Core Data uses them as
the most basic data methods to access data, consequently they do not
issue key-value access or observing notifications. Put another way,
they are to primitiveValueForKey: and setPrimitiveValue:forKey: what
public accessor methods are to valueForKey: and setValue:forKey:.
I would then expect the primitive accessor methods to be better performant then the public accessors because they do not trigger KVO notifications. Is there a way to effectively test this theory with Time Profiler? (Surely it can't be as easy as putting the two call in their own for-loops that iterate a zillion times and compare the results...)
Obviously the primitive accessors aren't to be called by objects or functions outside of the Managed Object subclass, but when shouldn't you use them from within the class?
edelaney05,
As you appear to know, Core Data depends upon the KVC/KVO features of Objective-C. Yes, you are correct that the path length is slightly longer through the accessors. What of it? Performance of Core Data is dominated by the performance of the I/O subsystem.
IOW, tuning your fetch request is much more important than avoiding the accessor overhead. Can you do what you're proposing? Yes. Should you? No. You should, IMO, focus upon how to get your data into a MOC efficiently and then refine it with predicates and other filter techniques. Learning how to use the various key path operators and predicate language after the fetch is very important to writing performant CD code. Only after Instruments can document that you are spending an appreciable amount of time in the accessors would I consider your strategy of avoiding them.
In answer to your specific question, you should generally restrict your use of the primitive accessors to within your reimplementation of the public accessors. Sticking with accessors for all of your code then becomes your standard pattern. This gives you the long term engineering benefit of having the ability to associate arbitrary behavior with any property. Finally, if you can use the various key path and set operators, then the CD team has already optimized those access patterns. They are quite performant.
Andrew
I have recently inherited a CoreData project from an outside developer. Where I expected to find all my auto-generated NSManagedObject sub-classes, I instead have (what some googling reveals to be) classes generated by Mogenerator, a tool that I have no experience with.
I understand that the purpose of using this tool is to make it so that you can add custom code into the classes corresponding to the CoreData entities without worrying about it being lost when the model changes and the classes are regenerated... but I can do this anyways by using categories.
I currently do not see a real advantage to using Mogenerator over categories.
What are the advantages/disadvantages of using Mogenerator vs. categories? Does Mogenerator serve any additional purposes?
An advantage of using classes vs categories, is that you can extend functionality by subclassing and overriding.
For instance, if your model has subentities, it is possible for them to inherit functionality from a common master class. Subclasses could define specific behavior by overriding the desired methods. On the other hand, it is possible to override methods defined in categories, but it is not recommended. This means logic implemented as categories would have to be repeated in every subclass.
A lot of code in managed objects is boilerplate, so it's really nice to have mogenerator do it automatically.
From their 'site' http://rentzsch.github.com/mogenerator/ :
mogenerator generates Objective-C code for your Core Data custom
classes
Unlike Xcode, mogenerator manages two classes per entity: one for
machines, one for humans
The machine class can always be overwritten to match the data model,
with humans’ work effortlessly preserved
So basically it got nothing to do with categories. Mogenerator (Model Object Generator) generates code which you've seen the results from in the project you've gotten handed over.
So Meta Programming -- the idea that you can modify classes/objects at runtime, injecting new methods and properties. I know its good for framework development; been working with Grails, and that framework adds a bunch of methods to your classes at runtime. You have a name property on a User object, and bamm, you get a findByName method injected at runtime.
Has my description completely described the concept?
What else is it good for (specific examples) other than framework development?
To me, meta-programming is "a program that writes programs".
Meta-programming is especially good for reuse, because it supports generalization: you can define a family of concepts that belong to a particular pattern. Then, through variability you can apply that concept in similar, but different scenarios.
The simplest example is Java's getters and setters as mentioned by #Sjoerd:
Both getter and setter follow a well-defined pattern: A getter returns a class member, and a setter sets a class member's value. Usually you build what it's called a template to allow application and reuse of that particular pattern. How a template works depends on the meta-programming/code generation approach being used.
If you want a getter or setter to behave in a slightly different way, you may add some parameters to your template. This is variability. For instance, if you want to add additional processing code when getting/setting, you may add a block of code as a variability parameter. Mixing custom code and generated code can be tricky. ABSE is currently the only MDSD approach that I know that natively supports custom code directly as a template parameter.
Meta programming is not only adding methods at runtime, it can also be automatically creating code at compile time. I.e. code generating code.
Web services (i.e. the methods are defined in the WSDL, and you want to use them as if they were real methods on an object)
Avoiding boilerplate code. For example, in Java you should use getters and setters, but these can be made automatically for most properties.