Core Data attribute changes to nil (ARC related?) - objective-c

I have some Core Data functionality that was working fine until some recent (seemingly unrelated) changes were made. Now I'm getting problems where all the attributes belonging to a particular NSManagedObject subclass instance are suddenly returning nil.
Let's say my NSManagedObject subclass is called Foo and it has only one attribute called value. Once I realised value was somehow becoming nil I went and setup the following category to monitor changes to value.
#implementation Foo (Debug)
- (void)setValue:(NSDate *)value
{
[self willChangeValueForKey:#"value"];
[self setPrimitiveValue:value forKey:#"value"];
[self didChangeValueForKey:#"value"];
}
- (NSDate *)value
{
[self willAccessValueForKey:#"value"];
NSDate *value = [self primitiveValueForKey:#"value"];
[self didAccessValueForKey:#"value"];
return value;
}
#end
setValue: is called for my object and the argument passed in is a non-nil NSDate. Then the value is retrieved (in another method). The same value that was specified is retrieved correctly.
However when another method tries to read value, the value accessor is called and a nil value is returned by primitiveValueForKey:.
In between the two reads setValue: is not called and the Foo object itself is still valid (non-nil). In fact no other Core Data operations are performed between the two reads on any Core Data object or the context as a whole.
We're using ARC in our project. Is it possible ARC is somehow messing with my Core Data variables and deallocating them? If so does anybody have any suggestions for debugging ARC deallocations? Or better yet, does anyone know a way to ensure ARC doesn't deallocate my variable.
This may not even be ARC related, however I'm at a bit of a loss as to what is going on. Any suggestions would be very much appreciated.

This is very likely because the NSManagedObjectContext that these objects belong to, is going away. When you have NSManagedObject instances around but you're not holding on to the context yourself, those managed objects will start returning nil.
Under ARC, make sure you store the context in a strong variable, i.e. an instance variable that's not weak or a static global.
Non-ARC, i.e. retain-release code, make sure you're retaining the context.

As others mentioned (it was my case also), be sure that you haven't reset your managed object context because if you do, all Entities stored as properties will have data: <fault>.
If you do reset your managed object context, you will also have to re-fetch the Entity itself.

check the viewDidLoad-Method
profile = [NSEntityDescription insertNewObjectForEntityForName:#"MyProfile" inManagedObjectContext:profileContext];
hope this works

Related

Adding and initialising a new property for an existing PFObject subclass

I have an existing Parse database, with several PFObject subclasses.
If I want to add a new property to a subclass, an array for example, I add it to the PFObject subclass as an #property and declare it #dynamic in the implementation. I initialise it as empty for new objects.
#dynamic newArray;
+ (instancetype)object
{
MyObject *myObject = [super object];
myObject.newArray = [NSMutableArray array];
return myObject;
}
But how can I ensure this is initialised for already existing objects, as accessing this property for old objects causes a crash.
I figured I could override the getter, but I would lose all the Parse boilerplate code, and not sure that's wise. Currently I have to empty my db to ensure all new objects have the right properties. But this obviously won't work in the real world.
This is a problem that I faced when developing my Parse application as well, but I did not have the problem of preexisting instances of the object that did not have a value for the specified key.
One solution to this problem would be to set up a cloud code job that runs through all the preexisting objects and assigns default values for the required fields. This would enable you to keep the complexity of the client to a minimum, allowing for easy updates and possibly porting to other systems.
You should also set up a beforeSave function that makes sure that all fields have a default value, and then either rejecting ones that don't or silently assigning them a default value.
My third and final recommendation (which you seem to be doing already) is to make sure the +object method properly initializes the object with all default values, in order to ensure that pinned objects (if you're using LDS) have the correct default value.

NSManagedObjectContext passed to NSWindowController becoming nil

I'm really scratchng my head trying to work out where my managed object context is vanishing to.
I'm originally instantiating it within my app delegate and then passing it into a retained property within an NSWindowController as such:
self.TPWC = [[TestPanelWindowController alloc] initWithWindowNibName:#"TestPanel"];
self.TPWC.managedObjectContext = self.managedObjectContext;
self.TPWC.persistentStoreCoordinator = self.persistentStoreCoordinator;
[TPWC.window makeKeyAndOrderFront:nil];
I've then got a button that should instantiate an NSManagedObject and insert it into the managed object context like this:
NSManagedObject *newInstanceOfSomeEntity =
[NSEntityDescription insertNewObjectForEntityForName:#"SomeEntity"
inManagedObjectContext:self.managedObjectContext];
At this point, self.managedObjectContext has somehow become nil.
I've inserted a breakpoint into windowDidLoad and I can confirm that at that point, we do have a valid instance of an NSManagedObjectContext, but it's somehow become nil in between viewDidLoad and then trying to insert a managed object.
I've tried creating a custom initialiser to set the NSManagedObjectContext but it's still becoming nil.
Core Data is quite new to me and I'm struggling to understand what's going wrong.
This is not a direct answer to why you're seeing your context disappear, but it could still fix your problem:
From an architecture standpoint, you really shouldn't be passing around the managed object context between objects, especially UI objects.
Instead you should have a global singleton class that instantiates the managed object context (along with the coordinator and persistent store, probably), and then provide access to it via a public property. Then, from your window controller, you would just access it from the singleton object.
(A side note if you're using multi-threading, be careful of accessing and using the same context from different threads.)

Is it ok to call release on a property in Objective C?

I've been teaching myself Objective C recently, and have noticed the following pattern used a lot in tutorials and sample code (including samples from the Apple site).
UIView *myUiView = [[UIView alloc] init];
self.uiView = myUiView;
[myUiView release];
I was just wondering though, it seems a bit of a waste to create a new variable, just to set a property. I've also seen the following pattern used too, but from what I understand its considered bad form to use autorelease on an iOS device as the autorelease pool takes up quite a bit of overhead which might not be good on a mobile device
self.uiView = [[[UIView alloc] init] autorelease];
I've been toying with using the following pattern recently, which sets the property, and then calls release on the property (to decrease the reference counter on the property itself).
self.uiView = [[UIView alloc] init];
[self.uiView release];
I've managed to use it on a few ViewControllers with no ill effects, but is this valid code, or am I missing something which makes it a bad idea?
The property getter is a method, and it does not have to return an ivar, it may actually get its return value anywhere, so you could release that, but it could be an autoreleased value already. If that is the case, you're in trouble.
IOW, if a property getter would do something like (not usual, but possible and valid):
- (NSString *) helloString
{
return [[myStringIVar copy] autorelease];
}
and you do:
[self.helloString release];
then you failed in two ways:
You did not release the ivar you wanted to release
You release an autoreleased object
IMO, it is better to release the ivar directly:
[myStringIVar release];
If the implementation of the property getter is simply to return the reference to the underlying ivar, then it is perfectly equivalent and you simply decrease the retain count of the allocated object.
On the other hand, if you can't be sure what the getter does (what if it returns something else than the ivar, e.g. some calculated result etc.), it may be dangerous.
No. It's not valid.
It will probably work on most retain properties but not necessarily. It will probably break on copy properties and assign properties.
Properties are just a pair of methods, one of which sets an abstract entity and one which gets it. There is absolutely no guarantee in general that the getter will give you the exact same object that you just passed to the setter. For instance, if you pass a mutable string to an NSString copy property, you definitely won't get back the same object.
Use either of the first two patterns. The first one does not waste anything. It is likely the local variable will only ever exist in a register. The overhead of the second will only last as long as the next autorelease pool drain and is only a few bytes (bear in mind that the actual object will last as long as self in any case).
It's not valid, and even in the cases where it does work its a bit "ugly" the other two are just to fix the property's retain characteristic from making the retain count 2 after having an alloc already making the retain count 1.
I tend to do what you described in the first example or the following.
in my #interface
#property (nonatomic, retain) UIView *uiView;
in my #implementation
#synthesize uiView = _uiView;
then when I setup the property.
_uiView = [[UIView alloc] init];
Thinking in terms of the reference counter, nothing is wrong with calling release using the property value. However, there are a few things, which I (personally) would dislike:
The property syntax is really just syntactic sugar for method calls. So, what your code really looks like, is
[self setUiView: [[UIView alloc] init]];
[[self uiView] release];
Another thing here might be more due to me thinking in strange ways, but I like to think of the reference counts as actually being related to references. A local variable holding a pointer to my object is such a reference. Having it present in the code reminds me, that I have something to do in order to clean things up properly (or, if not, at least write a short comment, why I don't have to clean up).
Directly going through the property forces me to think in terms of reference counts instead, which I don't like.

How to add alive object to NSMutableArray and remove them when they're released?

I have class Item and class List (which has an NSMutableArray).
Every time class Item is instantiated (and destroyed) it posts a notification, which is listened-to by class List. When class List receives the notification is adds the instance of class Item to its list.
I'm trying to have class Item also post a notification that its about to be dealloc'd. The problem is that class List's NSMutableArray retains the instance of class Item.
What's the most appropriate means of handling this situation? If I decrement the count when adding it to List's array, then an exception will be thrown when class List attempts to call removeObject (since it'll try to dealloc the object.)
Basically, I want a "monitor" class List that contains a list of all "live" instances of Item. But, I also need the ability to release/dealloc the instances and have them report they're being dealloc'd so List can remove them from its NSMutableArray.
Thanks for your help.
If I understand correctly, you want an array that maintains weak references to its items, as opposed to strong references?
I don't know of a way to do this with anything "built-in" in Cocoa. The only way I'd know of to do this is to make the array yourself, and have the storage be __weak id[]. That would automatically zero-out the place in the array when the object deallocates. If you're under the retain-release model, you could use something like MAZeroingWeakRef to get the same behavior.
This is definitely an interesting question, and I don't know of an easier answer. I'd love to be proven wrong!
Ha, I love being wrong!
There's a class called NSPointerArray that looks like it can do what you're looking for. However, it's only available on the Mac, and it only auto-zeros when you're using garbage collection.
I'll keep thinking about this. This is an interesting problem! :)
So I kept thinking about this, and came up with a solution. It uses two unconventional things:
A subclass of NSMutableArray (egads!)
Using an associated object to determine object deallocation
For the first bit, I had to to subclass NSMutableArray so that I could inject some custom logic into addObject: (and related methods). I didn't want to do this via swizzling, since NSArray and friends are a class cluster, and swizzling into/out of clusters is fraught with peril. So, a subclass. This is fine, but we're going to lose some of the awesome features we get from "pure" NSArray instances, like how they do weird things when they get big. Oh well, such is life.
As for the second bit, I needed a way for any arbitrary object to notify that it is about to or just finished deallocating. I thought of dynamically subclassing the object's class, injecting my own dealloc/finalize method, calling super, and then smashing the isa of the object, but that just seemed a little too crazy.
So, I decided to take advantage of a fun little thing called associated objects. These are to ivars what categories are to classes: they allow you to dynamically add and remove pseudo-instance variables at runtime. They also have the awesome side effect of getting automatically cleaned up with the object deallocates. So what I did is just created a little throw away object that posts a notification when it is deallocated, and then attached it to the regular object. That way when the regular object is deallocated, the throw away object will be as well, resulting in a notification being posted, which I then listen for in the NSMutableArray subclass. The notification contains a (stale) pointer to the object that is in the process of getting destroyed, but since I only care about the pointer and not the object, that's OK.
The upshot of all of this is that you can do:
DDAutozeroingArray *array = [DDAutozeroingArray array];
NSObject *o = [[NSObject alloc] init];
[array addObject:o];
NSLog(#"%ld", [array count]); //logs "1"
[o release];
NSLog(#"%ld", [array count]); //logs "0"
The source is on github, and it should (theoretically) work just as well on iOS as Mac OS X (regardless of GC mode): https://github.com/davedelong/Demos
Cheers!
... and I just thought of a way to do this without a custom subclass, but I'm tired and will post the updated answer tomorrow.
the next morning...
I've just updated the project on Github with an NSMutableArray category that allows you to create a true NSMutableArray that auto-zeroes its objects as they're deallocated. The trick was to create a CFMutableArrayRef with a custom retain callback that sets up the proper observation, and then just cast that CFMutableArrayRef to an NSMutableArray and use that (ah, the magic of Toll-Free Bridging).
This means you can now do:
NSMutableArray *array = [NSMutableArray autozeroingArray];
I added a typedef to define these as NSAutozeroingMutableArray, just to make it explicitly clear that while this is an NSMutableArray, it doesn't retain its objects like a normal NSMutableArray. However, since it's just a typedef and not a subclass, you can use them interchangeably.
I haven’t tested this, so comments are welcome.
You could use an NSPointerArray for the list (in a retain property):
self.array = [NSPointerArray pointerArrayWithWeakObjects];
When an Item object is created, it would post a notification that’s listened by your List class. Upon receiving the notification, List adds the object to the pointer array:
[array addPointer:pointerToTheObject];
In this setting, the pointer array doesn’t keep a strong reference to its elements — in particular, it doesn’t retain them. This applies to both garbage-collected and non-garbage-collected builds.
In a garbage-collected build, if an element is garbage collected then the garbage collector automatically assigns NULL to the position in the array where the object was stored.
In a non-garbage-collected build, you’ll need to manually remove the element or assign NULL to the position in the array where it was stored. You can do this by overriding -[Item dealloc] and posting a notification that the object is being deallocated. Your List class, upon receiving the notification, would act upon it.
Note that, since objects are not owned by the pointer array, you must keep a strong reference to (or retain) them if you want to keep them alive.

Cocoa ivar losing value between init and drawRect

I am not a complete n00b here, but I feel like I must be missing something essential. I'm passing a variable into a new class instance via the class's init method:
#synthesize side;
- (id)initWithSide:(NSString *)aSide frame:(NSRect)frameRect
{
if (self = [super initWithFrame:(NSRect)frameRect]) {
self.side = aSide;
}
NSLog(#"Side is %#", self.side);
return self;
}
The output from NSLog() does show the correct value here. Now, the drawRect: method that is then triggered to draw the view, has a similar call:
- (void)drawRect:(NSRect)rect
{
NSLog(#"Side is %#", self.side);
And this time the NSLog() reports Side as nil! Stepping through it with the debugger, I see the value for side gets set, then it goes into the registers (all those hex codes that I don't understand), then when it jumps out again into the drawRect: method, the value is simply nil.
If anyone can shed light on this I'd appreciate it!
Cheers,
Aaron
This is usually the way to write a property for NSString*.
assign is used for primitive types (it doesn't increment the retain count for an object), and either retain or copy for Objects.
#property (readwrite, copy) NSString * side
I'm going to go ahead and guess the most common cause for this kind of bug: You're dealing with two different objects. You're initializing the view in your code and you also have an instance in a nib. The two instances are completely separate objects, so when the view that is visible performs its drawRect:, it doesn't see the other one's instance variable.
The problem with your property that other people are pointing out is also definitely true, but I suspect this bug is actually hiding that one.