Mutable sets in NSManagedObjects? - iphone

The standard declaration for an autogenerated NSManagedObject property declares to-many relationships like this:
#property (nonatomic, retain) NSSet *somethings;
...
#dynamic somethings;
Would it be safe to change that declaration to an NSMutableSet? Would the CoreData component still function correctly?
Judging by the #dynamic, it probaby doesn't care if I use an NSSet subclass rather than an NSSet, but I don't want to rewrite a lot of code only to find out it doesn't work.

According to Apple's Core Data Programming Guide, this should always be declared as a NSSet.
If you want a mutable proxy (which is basically the mutable version of the core data set and works exactly the same) then you would use the function mutableSetValueForKey like this:
// myManagedObject is the managed object that has the somethings property.
NSMutableSet *mutableSomethings = [myManagedObject mutableSetValueForKey:#"somethings"];
mutableSomethings can then be modified as a standard NSMutableSet andsomethings will be updated and KVO methods will be appropriately called.
Note however, that many features of the mutable set (such as addSomethingsObject and removeSomethingsObject) are already provided in the core data generated accessors so in many cases you don't need to use the proxy.

You should keep it as an NSSet and do one of the following:
Use key value coding
Add the core data generated accessors
For key value coding, you'll access your collection like so:
NSMutableSet *somethings = [object mutableSetValueForKey:#"somethings"];
[somethings addObject:newObject];
For core data generated accessors, you'd add the following to your header:
#interface MyManagedObject (CoreDataGenerated)
- (void)addSomethingsObject:(MySomething *)object;
- (void)removeSomethingsObject:(MySomething *)object;
- (void)addSomethings:(NSSet *)somethings;
- (void)removeSomethings:(NSSet *)somethings;
#end
You do not need to implement these methods (Core Data will take care of it for you), and you can call them easily. This is my preferred way of handling collections because you get better type checking from the compiler.
The reason you should not change it to an NSMutableSet is because there is a good chance that you will cause crashes and/or that your changes will not be persisted into your Core Data store.
You may also want to look into mogenerator to help you out with creating all of your Cocoa classes.

Related

Internal properties versus ivars

When I need a private object I currently use properties, like so:
// Class extension in .m file
#interface MyClass()
#property (strong, nonatomic) NSArray* myInternalArray;
#end
self.myInternalArray = something;
Alternatively you can do this:
#implementation MyClass {
NSArray* _myInternalArray;
}
_myInternalArray = something;
Without a custom setter or getter the two are equivalent. What is the best practice for internal variables? Are there any advantages of one method over the other?
While some may argue that the choice is a matter of preference, and they do have a point, there is a very good reason that most modern languages support properties and make them easier and easier to code.
The introduction of ARC does not significantly reduce the value of properties. It all comes down to this - in a property you have encapsulated the use of a variable. That encapsulation is invaluable when needed, and not much overhead when it is not.
For example (off of the top of my head) Suppose you discovered that you needed to validate the value before saving it. If you were using an iVar, you would have to ensure that anywhere that iVar was used, you had a call the validation code before you allowed it's value to be changed. With a property, you would only need to override setIVarName: and put the validation there. One could argue that one is just as easy as the other - and that may be true in many cases, but there is one handicap with the iVar here - you cannot ensure that future changes (by you or other coders) will insert the validation before the iVar is changed. Using a property here does have that assurance.
Personally, I use properties over iVars where ever possible.
I'd say that the advantage of properties is that you would use setters, and that setters can evolve independently of the code that call them. For instance, you could decide that setting a property would now trigger setNeedsLayout. By using properties from the start, you would have no need to refactor existing code.
This pattern fits very well in Cocoa/iOS APIs, where you don't have to ask system objects to do anything after having changed their properties: setters ensure internal and UI consistency right away.
The fact that properties are private should not make us implement them as second-class properties, what do you think?

iPhone - Change entity class (NSManagedObject) to make them initializable

I would like to use my custom NSManagedObject like a normal object (as well as its regular functions). Is it possible to modify the class in order to be able to initialize it like a normal object?
[[myManagedObject alloc] init];
Thanks
edit: to clarify the question, will it screw everything up if I change the #dynamic with #synthesize in the implementation?
I do this quite often in one of my apps. My approach is to initialize the object with:
-(id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
passing nil for the context. To get the entity description, you do need access to the managedObjectContext. I tend to get the entity description when my app starts and then store it in an instance variable in my app delegate.
Here's an example:
//inside my "Engine" class
self.tweetEntity = [NSEntityDescription entityForName:#"Tweet" inManagedObjectContext:self.moc];
//later on when I want an NSManagedObject but not in a managed object context
Tweet *tweet = [[[Tweet alloc] initWithEntity:self.engine.tweetEntity insertIntoManagedObjectContext:nil] autorelease];
This allows me to use NSManagedObjects without storing them in a database. Later on, if I decide I do want the object inserted into my database, I can do it by inserting it into my managed object context:
[self.moc insertObject:tweet];
The managed object context is a required property of NSManagedObject therefore you can't properly initialize an instance of it without inserting it into a context. It looks at the context to understand it its entity and it notifies the context when any of its properties change.
The #dynamic and #synthesize are just compiler directives. You can switch to #synthesize from #dynamic as long as you provide proper getters and setters yourself. Since NSManagedObject relies heavily on key-value observing to function, you do have to write KVO compliant accessors.
If you need to initialize an NSManagedObject subclass, you override awakeFromInsert which will let you provide customization to the instance when it is created. You can also customized the object every time it is fetched using awakeFromFetch.

Why does Core Data create NSManagedObject's with properties but no accompanying instance variable?

Exactly as the title says, why does Core Data create instances of NSManagedObject with properties for each entity's attribute, but no accompanying instance variable? The problem is, I would like to use some of my 'Entities' in a typical alloc/init style fashion in some parts of my code. Not using Core Data's fetching/context to create/store.
I suppose I could stay without the instance variables, but would it hurt to add them? Can I also change the #dynamic to #synthesize so I can use KVC on my properties/ivars?
Perhaps I'm completely wrong in trying to use one of my Core Data entities in some parts of my code without using the core data APIs. Still rather new to it to understand when I can go my own route.
The reason it doesn't use ivars is that that data isn't there. When you load an object it may not fault in all of its data. ivars are just variables, if you and write to them NSManagedObject doesn't have a chance to fault in the value if it has not been loaded yet. Via accessors NSManagedObject has a choke point that allows it to read the data off the disk if it has not been faulted in yet, which means your object graph can be brought in lazily. Otherwise you would need to bring in every connected object.
Because of that, you can't just add ivars, they won't have the values you want. Likewise you can't change from #dynamic to #synthesized, things will not behave correctly. The dynamic property implementations provided by CoreData are completely KVC and KVO compliant anyway.
If you want to access the values without tripping KVO or KVC you can access the "primitive" values. You do that in one of two ways. You use primitiveValueForKey: and setPrimitive:valueForKey: or you can just declare the primitive and let CD provide dynamic implementations (from the documentation)
#interface Department : NSManagedObject
{
}
#property(nonatomic, retain) NSString *name;
#end
#interface Department (PrimitiveAccessors)
- (NSString *)primitiveName;
- (void)setPrimitiveName:(NSString *)newName;
#end
You don't need instance variables with Core Data. A managed object stores these values elsewhere.
I've never gotten very far with Core Data, but if I remember correctly, you're supposed to use primitiveValueForKey: and setPrimitiveValue:forKey: to perform these accesses from your accessor methods. (Outside of your accessors, you should be using either the accessors themselves or valueForKey:/setValue:forKey: instead.)

Is there any way to automatically generate #property and #dynamic tags for Core Data primitive accessors?

Update: mogenerator works, with a template modification
The Core Data documentation suggests using the -primitiveValue and -setPrimitiveValue: methods to access and change internal data of an NSManagedObject subclass rather than the slower and non-type-checked -primitiveValueForKey: and setPrimitiveValue:forKey:.
I would like to adopt this change in my code but in order to avoid compiler warnings I need to add #property and #dynamic declarations to my managed object classes for all those primitive accessors. Xcode is happy to generate all that code for me, but only for the public accessors to the object (-value rather than -primitiveValue).
Is there any automated method, either through Xcode or an external program that can scan the .xcdatamodel file, to generate those primitive accessors for me so I don't have to type them all out in all 16 of my managed classes?
Have a look at mogenerator (GitHub).

How to access fetched property in Objective-C 2.0 using Core data

I'm new to IPhone development and I'm currently trying my hand at Core Data. I have a couple of entities that I've defined in my model. In one entity I have a fetched property. When I generate the Objective-C source files from my model, my entity that I defined with the fetched property does not have a property defined for the fetched property. Why? How do I access the fetched property?
More details in response to Tim:
I have an entity named Library and another entity named Book.
Library has a one to many relationship to Book (Book also has an inverse relationship).
Book has a BOOL property called isCheckedOut.
I defined a fetched property on Library called fetchAllCheckedOutBooks. The destination entity is Book and the predicate is isCheckedOut == 1.
Have you tried using valueForKey: and passing in the name of your fetched property? That's how I would expect it to work. I would also expect that it would return an NSSet object, but that's easily verified by doing this:
id results = [myManagedObject valueForKey:#"fetchedPropertyName"];
NSLog(#"%#", [results className]);
Yeah, this is annoying....
Fetched properties are returned as an NSArray, so you just have to add it yourself:
//.h
#property (nonatomic, retain) NSArray *fetchedPropertyName;
//.m
#dynamic fetchedPropertyName;
yeah, really odd that Xcode doesn't include this when it generates the NSManagedObject subclass like it does for regular attributes and relationships