Problem adding object to NSMutableArray - objective-c

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;

Related

Order of instance variable assignments freezes iOS app

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.

Why does my NSArray get deallocated?

I'm trying to understand Automatic Reference Counting, as I come from a high-level programming language (Python) and I'm working on a project which use this feature of Objective-C. I often get problems with ARC deallocating objects which I need later, but now I got a concrete example for which I hope I'll get an explanation.
- (void) animateGun:(UIImageView *)gun withFilmStrip:(UIImage *)filmstrip{
NSMutableArray *frames = [[NSMutableArray alloc] init];
NSInteger framesno = filmstrip.size.width / gun_width;
for (int x=0; x<framesno; x++){
CGImageRef cFrame = CGImageCreateWithImageInRect(filmstrip.CGImage, CGRectMake(x * gun_width, 0, gun_width, gun_height));
[frames addObject:[UIImage imageWithCGImage:cFrame]];
CGImageRelease(cFrame);
}
gun.image = [frames objectAtIndex:0];
gun.animationImages = frames;
gun.animationDuration = .8;
gun.animationRepeatCount = 1;
[gun startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:leftGun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
}
The idea behind this snippet of code is simple: I have a (UIImageView*)gun which I animate with the images stored in (NSMutableArray *)frames, at random times. (UIImage *)filmstrip is just an image which contains all the frames which will be used on animation. The first iteration of animation works, but the problems appears on the second iteration, where I get -[UIImage _isResizable]: message sent to deallocated instance ... or -[UIImage _contentStretchInPixels]: message sent to deallocated instance ... or -[NSArrayI release]: message sent to deallocated instance .... This happens at
gun.animationImages = frames;
but I don't understand why. I'm not requesting a fix for my issue, but just to help me understand what's happening here. Thanks.
ARC is a mechanism that removes the need to manually retain/release objects. Here's a nice site that explains how this works: http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
Try changing "leftGun" for "gun". I think that's probably the one that gets deallocated at some point, if you're using it through an ivar. Otherwise, leftGun simply isn't in the scope.
Here's what it should look like:
In your .h file:
#property (nonatomic, strong) IBOutlet UIImageView *leftGun;
In your .m file:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:gun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
Also, not quite sure where "gunShoot" is coming from. Is that supposed to be an enum?
EDIT
Added an example of how the leftGun property should be defined. The reason behind using a property over an ivar is for memory management purposes. If you want to release or destroy an object that is a property, simply set it to nil and the property will take care of releasing the object if it has to.
You may prevent the deallocation of the frames array if you mark it as __block.
__block NSMutableArray *frames = [NSMutableArray array];
see “The __block Storage Type.”

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.

iPhone EXC_BAD_ACCESS with NSMutableArray of strings

Problem context is a ViewController with several button handlers and a scores.list data file of 1000 NSString objects. If I click on buttonOne, the handler code checks if the file scores.list exists in the User Documents directory. If yes, it loads the data in an NSMutableArray called score, if not it creates the NSMutableArray in memory (to be stored on disk later) like this:
- (void)readScores
{
// Setup path + filename pathUserDocDirScorelist);
...
// test for presence scores.list in documents dir
if ([fileManager fileExistsAtPath: pathUserDocDirScorelist])
{ // Read scores.plist into NSMutableArray
score = [NSMutableArray arrayWithContentsOfFile:pathUserDocDirScorelist];
} else { // Initialize empty scores array with 1000 empty NSString entries
score = [[NSMutableArray alloc] init];
int i;
for(i = 0; i < 1000; i++) {
[score addObject:#""];
}
}
// at this point there is always a valid array score with 1000 entries
}
Basically this code works; in both cases (reading data from scores.list or in-mem build-up) I can verify in the debugger (with 'po score') that an array with 1000 entries is present afterwards.
Now comes the problem that is blocking me for 2 days now:
In the handler of buttonTwo, statements like [score count] crash, but only in case the array score gets its data from disk, not if build-up in memory. In the first case is the array still valid though until the last line of handler code of buttonOne, but then 'evaporates' as soon as the array is addressed in a next handler (EXC_BAD_ACCESS).
No, it is not caused by a premature release statement, since there are none (yet) in my entire app. :)
(not concerned with memory leaks yet).
How is this possible that within one view a NSMutableArray is valid at the end of button handler 1, but invalid at the beginning of the next button handler 2 if no explicit release statement is executed in between?
Extra info:
ViewController.h:
#interface ViewController : UIViewController {
NSMutableArray *score;
...
}
#property (nonatomic, retain) NSMutableArray *score;
...
- (IBAction) buttonOne: (id) sender;
- (IBAction) buttonTwo: (id) sender;
#end
And in ViewController.m I have:
#synthesize score;
...
- (IBAction) buttonOne: (id) sender {
if (score == nil) {
[self readScores];
}
...
NSLog(#"Number of entries in score = %i", [score count]); // never crashes
}
- (IBAction) buttonTwo: (id) sender {
NSLog(#"Number of entries in score = %i", [score count]); // **crash point**
}
P.S. I tried NSZombieEnabled by starting the app with alt/cmd/R and adding 'NSZombieEnabled=YES', but that does not result in extra information in the debug console.
It's always a little dangerous to do this:
score = [[NSMutableArray alloc] init];
outside of an init method. Because, the problem is that perhaps your method readScores is executed twice. I'd guess it almost certainly is.
What happens then is the the first scores object is never released. That causes a memory leak and sooner or later you get the dreaded EXC_BAD_ACCESS.
So, the best thing is either to first check:
if (score)
{
[score release];
}
Or, alternatively, set up scores as a synthesized retained object in your .h file. Then you can replace your code as follows and let everything happen automatically:
self.scores = [NSMutableArray array];
Note that here, I didn't use:
self.scores = [NSMutableArray alloc] init];
because that would cause two retains to happen, and of then EXC_BAD_ACCESS due to over-retention.

Memory leaks while using NSMutableArray

Hi guys can somebody please advise how to cure the memory leaks in the code below
i've tried just about every combination of release and autorelease i can think of but every time either the app crashes or the leak remains
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
//get refereance to the textfield
UITextField *currentTextField = (UITextField*)[self.view viewWithTag:200];
//check which picker
if(pickerView.tag ==1)
{
// Only calls the following code if component "0" has changed.
if (component == 0) {
// Sets the global integer "component0Row" to the currently selected row of component "0"
component0Row = row;
// Loads the new values for the selector into a new array in order to reload the data.
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
currentValues = newValues;
// Reloads the data of component "1".
[pickerView reloadComponent:1];
}
//run the selector logic
[self textFieldDidEndEditing:currentTextField];
}
hope someone can advise
many thanks
Your problem is these two lines:
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
currentValues = newValues;
The first line allocated a new instance of NSMutableArray. The second line copies the pointer from newValues to currentValues, overwriting the pointer value in currentValues. Whatever currentValues was pointing to is lost. That's the leak.
You could fix it like this:
newValues = [[NSMutableArray alloc] init...
[currentValues release];
currentValues = newValues;
This way, whatever was pointed to by currentValues has its reference count decremented before you lose access to it.
You could also solve the problem by making currentValues an Objective-C property, and using the accessor methods via self.currentValues or [self setCurrentValues:]; those methods will handle retain/release for you.
Your NSMutableArray allocation is never released.
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
You should autorelease that or release it later on when you know you don't need it anymore.
Not sure how you have currentValues defined, but this should work without leaks:
In your .h file:
#property (nonatomic, retain) NSArray * currentValues;
In your .m file:
#synthesize currentValues;
self.currentValues = newValues;