Order of instance variable assignments freezes iOS app - objective-c

In my header, I have two properties as shown below.
#interface HZCalendarDataSource : NSObject
#property (strong, nonatomic) NSMutableArray *datesOnCalendar;
#property (strong, nonatomic) HZCalendarDay *currentDay;
#end
Then in my implementation's initializer, I have the following lines of code.
- (id)init {
self = [super init];
if (self) {
// Alloc / Init instance variables.
self.datesOnCalendar = [[NSMutableArray alloc] init];
self.currentDay = [[HZCalendarDay alloc] init];
HZCalendarDay *date = [[HZCalendarDay alloc] initOnDate:today withEventStore:self.eventStore];
[self.datesOnCalendar addObject:date];
// THIS line causes the app to freeze!
// If this line is above [self.datesOnCalendar addObject:date];
// Then it does not freeze. Why does this happen?
self.currentDay = date;
}
return self;
}
The issue that I have, is that as shown in the comments, the self.currentDay = date; line freezes the app on the device. However, if I move the self.currentDay = date; line above the line where the date object is added to the NSMutableArray, then the code works just fine.
So my question is, why does the order of this matter? It should just be setting self.currentDay to reference the same date object that I added to the NSMutableArray correct?
I'd appreciate it if someone could explain this to me, I'm not understanding it. The order doesn't really matter, so for now I've moved the troublesome line to be executed prior to adding the date object to the array, however for educational purposes, I'd like to know why this is an issue in the first place.
Edit:
After letting the app run frozen for awhile, it finally failed in Xcode after invoking [HZCalendarDateSource setCurrentDay:] 25,827 times. It failed with EXC_BAD_ACCESSS in the debugger and -[__NSArrayM countByEnumeratingWithState:objects:count:];
Hope this helps.
Thanks!

So I figured it out, after re-reading the error message, it sounded like the setter was failing for some reason, even though I'm not implementing it.
However, I had wrote a helper method to loop through my array and perform some actions on an item that matches the args i provide it. I had called that helper method setCurrentDay:, thus I had a naming conflict. My code was getting stuck in a for-loop that I had wrote. The for-loop scanned the self.datesOnCalendar property, and when self.currentDay = date; was executed prior to adding the object to the array, the setCurrentDay: method would return, because the array was empty. Setting the currentDay after adding an object to the array was causing my setCurrentDay: method to get stuck in a loop.
Fix was to rename the setCurrentDay: method to something that does not conflict with the setter of the currentDay property, along with adjusting my for-loop.

Related

In objective c can a class essentially delete itself?

In objective c, suppose I have an object Obj stored in a NSMutableArray, and the array's pointer to it is the only strong pointer to Obj in the entire program. Now suppose I call a method on Obj and I run this method in another thread. In this method, if Obj sets the pointer for itself equal to nil will it essentially delete itself? (Because there will be no more strong pointers left) I suspect the answer is no, but why? If this does work, is it bad coding practice (I assume its not good coding, but is it actually bad?)
It is highly unlikely that an object would be in a position to cause its own release/deallocation if your code is designed properly. So yes, the situation you describe is indicative of bad coding practice, and can in fact cause the program to crash. Here is an example:
#interface Widget : NSObject
#property (retain) NSMutableArray *array;
#end
#implementation Widget
#synthesize array;
- (id)init
{
self = [super init];
if(self) {
array = [[NSMutableArray alloc] init];
[array addObject:self];
}
return self;
}
- (void)dealloc
{
NSLog(#"Deallocating!");
[array release];
[super dealloc];
}
- (void)removeSelf
{
NSLog(#"%d", [array count]);
[array removeObject:self];
NSLog(#"%d", [array count]);
}
#end
and then this code is in another class:
Widget *myWidget = [[Widget alloc] init];
[myWidget release]; // WHOOPS!
[myWidget removeSelf];
The second call to NSLog in removeSelf will cause an EXC_BAD_ACCESS due to the fact that array has been deallocated at that point and can't have methods called on it.
There are at least a couple mistakes here. The one that ultimately causes the crash is the fact that whatever class is creating and using the myWidget object releases it before it is finished using it (to call removeSelf). Without this mistake, the code would run fine. However, MyWidget shouldn't have an instance variable that creates a strong reference to itself in the first place, as this creates a retain cycle. If someone tried to release myWidget without first calling removeSelf, nothing would be deallocated and you'd probably have a memory leak.
If your back-pointer is weak (which it should be since a class should never try to own it's owner, you will end up with a retain-cycle) and you remove the strong pointer from the array the object will be removed from the heap. No strong pointers = removed from memory.
You can always test this.
If you need a class to bring to a situation where its deleted, the best practice is to first retain/autorelease it and then make the situation happen. In this case the class won't be deleted in a middle of its method, but only afterwards.
I think we can say it might be bad coding practice, depending on how you do it. There are ways you could arrange to do it safely, or probably safely.
So let's assume we have a global:
NSMutableArray *GlobalStore;
One approach is to remove yourself as your final action:
- (void) someMethod
{
...
[GlobalStore removeObject:self];
}
As this is the final action there should be no future uses of self and all should be well, probably...
Other options include scheduling the removal with a time delay of 0 - which means it will fire next time around the run loop (only works of course if you have a run loop, which in a thread you may not). This should always be safe.
You can also have an object keep a reference to itself, which produces a cycle and so will keep it alive. When its ready to die it can nil out its own reference, if there are no other references and that is a final action (or a scheduled action by another object) then the object is dead.

Object alloc init irregularities

I'm seeing some disturbing irregularities concerning object allocation and initialization in an app I'm trying to write.
I have a 'root' Modelcontroller object, which in turn contains references to subcontrollers. The root controller is called modelController, and in it's init method it allocates and inits the subcontrollers like so:
- (id)init
{
NSLog(#"%#", #"ModelController begin init");
self = [super init];
if (self) {
LibraryController * tempLibrary = [[LibraryController alloc] init];
self.library = tempLibrary;
StoresController * tempStores = [[StoresController alloc] init];
self.stores = tempStores;
CLLocationManager * tempLocationManager = [[CLLocationManager alloc] init];
self.locationManager = tempLocationManager;
}
NSLog(#"%#", #"ModelController complete init");
return self;
}
Pretty standard. The subcontrollers' init code also contain an NSLog messages at the beginning and the end, for me to be able to see that all is well.
The properties are defined as
#property (strong) LibraryController * library;
#property (strong) StoresController * stores;
#property (strong) CLLocationManager * locationManager;
And I am using ARC.
What puzzles me is that sometimes I see the NSLogs from one of the subcontrollers, but not from the root controller. Sometimes I see the 'begin init' log message from the root controller, but not the 'complete init'. Sometimes I see no init log messages. The application launches anyway in any of these cases.
This happens seemingly at random, in one out of five launches or in one out of twenty launches. When it happens, the app acts very strange (but not every time, mind you), beachballing for no apparent reason and exhibiting general wonkiness.
As a side note, at one time I put a breakpoint in the init method of the StoreController class, which when pausing executing spit out a chunk of random data in the debugging console:
$m2303,3503,3603,3703,3803,3903#00$m2303,3503,3603,3a03#00$88ee410901000000981e420901000000001e42090100000060ee410901000000b062f668ff7f000070044391ff7f0000f00e0800000000000300000068200100dc62f668ff7f0000d862f668ff7f00000000000000000000717ddd8aff7f00000000000068200100801e420901000000000000000600000706000007000000007063f668ff7f000003280000000000007863f668ff7f000001ee410901000000f062f668ff7f00006c5bd391ff7f000000000000ff7f0000ab064391ff7f000000000000ffffffff032800000000000040
...and so on
Where should I begin to look to troubleshoot this?
The modelController is alloc init'd from the MyDocument equivalent class, and is modeled as a singleton.
The singleton implementation looks like this:
static ModelController *sharedModelController = nil;
+ (ModelController*)sharedManager
{
if (sharedModelController == nil) {
sharedModelController = [self new];
}
return sharedModelController;
}
Final note: I have tried removing the locationManager stuff and disabling/enabling the 'Restore state' preference in the scheme, but to no avail.
Sounds like you're doing some UI stuff not on the main thread.
This generally leads to weird behavior.
Make sure you call everything UI related on the main thread
Best guess: the ModelController object is being released. Perhaps the Singleton is faulty.

Problem adding object to NSMutableArray

I am having problems adding objects to my NSMutableArray. It seems that something gets added (object count increases by 1 in debugger), but the only thing added is a 0x0 (null) instead of the address of an object. I've read through everything somewhat relevant that I could find, but I couldn't find anything that seemed to answer this issue. Most related posts seem to revolve around memory management, but the solution is not jumping out at me.
I appreciate any help you can provide.
I've included what I think are the relevant parts of the code. Please tell me if you need to see anything more.
GamePlayView.h
#interface GamePlayView : UIViewController
{
Player *gamePlayer;
NSMutableArray *boardObjects;
}
#property (retain, nonatomic) Player *gamePlayer;
#property (retain, nonatomic) NSMutableArray *boardObjects;
#end
GamePlayView.m
- (void)viewDidLoad
{
// Create player
Player *tempPlayer = [[Player alloc] initWithFrame: self.view.frame];
if (tempPlayer == NULL) {
NSLog(#"GamePlayView viewDidLoad: null Player");
}
else gamePlayer = tempPlayer;
// Create array of board objects
NSMutableArray *newArray = [[NSMutableArray alloc] init];
self.boardObjects = newArray;
[self.boardObjects addObject: gamePlayer]; // First breakpoint here
topObject = 0;
BoardObject *mine = [[BoardObject alloc] initWithFrame: self.view.frame];
[self.boardObjects addObject: mine]; // Second breakpoint here
topObject = 1;
[super viewDidLoad];
} // End viewDidLoad
I put breakpoints at the addObject lines (commented in code). When execution stops at the first breakpoint, the debugger shows a good tempPlayer, and a good gamePlayer (both with the same address). It shows 0 objects in boardObjects, like this:
boardObjects = (_NSArrayM *) 0x4b22080 0 objects
When I step over this breakpoint, the debugger shows 1 object in boardObjects, as follows:
boardObjects = (_NSArrayM *) 0x4b22080 1 objects
0 = (NSObject *) 0x0
When I continue program execution, and the debugger stops at the next breakpoint, I also see a good mine object, with boardObjects still described as above. After stepping over this breakpoint, boardObjects now looks like this:
boardObjects = (_NSArrayM *) 0x4b22080 2 objects
0 = (NSObject *) 0x0
1 = (NSObject *) 0x0
This could be the case that tempPlayer is a local variable, after returning from the function, the local variable is automatically released.
Someone suggested I display the boardObjects in the code anyway, even though it looked from the debugger that I only had null objects. I inserted this code after the last addObject:
NSLog(#"self.boardObjects is: %#", [self.boardObjects description]);
This displayed good objects: the gamePlayer and the mine!
I did verify that immediately before this NSLog statement, and immediately after, the debugger still displays two null entries in boardObjects.
It seems like the answer to my original question, then, is that the code itself is correct. However, it seems now that I have a new question: Does this mean I'll never be able to view into an NSMutableArray from within the debugger?
You should assign #property with self.
self.gamePlayer = tempPlayer;

Accessing property inside non-init methods gives bad access

I've begun work on a side project, so the codebase is very small, very little that could go wrong. Something strange is happening. In viewDidLoad I initialise an array set as a property:
#property (nonatomic, retain) NSMutableArray * story_array;
And fill it with data. This printout is fine:
NSLog(#"%#", ((ArticlePreview *)[self.story_array objectAtIndex:0]).article);
I have a gesture recognizer:
UITapGestureRecognizer * openStory = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showStory)];
Tapping on it calls a method whose first line is this (i.e. the same NSLog):
NSLog(#"%#", ((ArticlePreview *)[self.story_array objectAtIndex:0]).article);
But this causes a bad access. Accessing story_array itself is fine (it'll say it has however many ArticlePreview objects inside) but accessing their fields is a no-no.
The story_array is init'ed as follows:
self.story_array = [[NSMutableArray alloc] init];
Assignment to the fields of the ARticle Preview object were not done properly. I had:
someField = someValue;
I needed:
self.someField = someValue;
I still find that a bit crazy, but there you go. Solved.

Crash in OS X Core Data Utility Tutorial

I'm trying to follow Apple's Core Data utility Tutorial. It was all going nicely, until...
The tutorial uses a custom sub-class of NSManagedObject, called 'Run'. Run.h looks like this:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Run : NSManagedObject {
NSInteger processID;
}
#property (retain) NSDate *date;
#property (retain) NSDate *primitiveDate;
#property NSInteger processID;
#end
Now, in Run.m we have an accessor method for the processID variable:
- (void)setProcessID:(int)newProcessID {
[self willChangeValueForKey:#"processID"];
processID = newProcessID;
[self didChangeValueForKey:#"processID"];
}
In main.m, we use functions to set up a managed object model and context, instantiate an entity called run, and add it to the context. We then get the current NSprocessInfo, in preparation for setting the processID of the run object.
NSManagedObjectContext *moc = managedObjectContext();
NSEntityDescription *runEntity = [[mom entitiesByName] objectForKey:#"Run"];
Run *run = [[Run alloc] initWithEntity:runEntity insertIntoManagedObjectContext:moc];
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
Next, we try to call the accessor method defined in Run.m to set the value of processID:
[run setProcessID:[processInfo processIdentifier]];
And that's where it's crashing. The object run seems to exist (I can see it in the debugger), so I don't think I'm messaging nil; on the other hand, it doesn't look like the setProcessID: message is actually being received. I'm obviously still learning this stuff (that's what tutorials are for, right?), and I'm probably doing something really stupid. However, any help or suggestions would be gratefully received!
===MORE INFORMATION===
Following up on Jeremy's suggestions:
The processID attribute in the model is set up like this:
NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc]init];
[idAttribute setName:#"processID"];
[idAttribute setAttributeType:NSInteger32AttributeType];
[idAttribute setOptional:NO];
[idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];
which seems a little odd; we are defining it as a scalar type, and then giving it an NSNumber object as its default value. In the associated class, Run, processID is defined as an NSInteger. Still, this should be OK - it's all copied directly from the tutorial.
It seems to me that the problem is probably in there somewhere. By the way, the getter method for processID is defined like this:
- (int)processID {
[self willAccessValueForKey:#"processID"];
NSInteger pid = processID;
[self didAccessValueForKey:#"processID"];
return pid;
}
and this method works fine; it accesses and unpacks the default int value of processID (-1).
Thanks for the help so far!
If you are getting EXC_BAD_ACCESS on
[run setProcessID:[processInfo processIdentifier]];
it's almost certainly due to one of the pointers no longer pointing to a real object. Either run has been dealloc'd or processInfo has been dealloc'd. This assumes that the line is not the next line of code after
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
If it is, then both objects should be valid, so you are probably looking at something wrong with
[self willChangeValueForKey:#"processID"];
or
[self didChangeValueForKey:#"processID"];
if you have any objects observing that key, it's possible they have gone stale somehow.
This did not solve my problem with willAccessValueForKey but it solved a mystery. I subclassed an entity but I forgot to set the custom class in the model. The custom class worked until I wrote a method to send back a string which was a concatenation of some of the properties. The method was nearly identical to another method that was in another custom NSManagedObject class. I could not figure out why the one class worked and the other didn't. Once I set the custom class in the model they both worked.