Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

fergusjk

macrumors member
Original poster
Aug 23, 2010
44
0
Ayrshire Coast, Scotland
I have a UITableView which I am trying to set up. The sections should have titles and each section will have a different number of rows.

If I hardwire the return data in, then it works, however if I try and pull the data from NSMutableArrays in the relevant methods then the app crashes with no explanation in the console.

To summarise
Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

	//return [[sectionNumberRows objectAtIndex:section] intValue];
	return 5;
}
works (giving me 5 rows per section)

but
Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

	return [[sectionNumberRows objectAtIndex:section] intValue];
	//return 5;
}
doesn't

the code (placed in viewDidLoad)
Code:
for (int i = 0; i < [sectionNumberRows count]; i++) {
		NSLog(@"sectionNumRows[]=%d", [[sectionNumberRows objectAtIndex:i] intValue]);
		
}
outputs
sectionNumRows[]=1
sectionNumRows[]=4
as i would expect.

What am I doing wrong in the numberOfRowsInSection method?

This behaviour is repeated in the titleForHeaderInSection method. i.e. if I hardwire the return string
return @"testing";
then the app works (with two section titles of 'testing')
but if I try accessing the names from an NSMutableArray
return [sectionTitles objectAtIndex:(int)section];
then, again, it falls over with no explanation in the console.
 
The madness continues...

I tried running it in debug mode and it worked first time - picking up the titles from the array and not crashing. I changed NOTHING and i tried running it again and it crashed with this error in debug mode

Program received signal: “EXC_BAD_ACCESS”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)

I pressed continue a couple of times but get the same error.

(gdb) continue
Program received signal: “EXC_BAD_ACCESS”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
(gdb) continue
Program received signal: “EXC_BAD_ACCESS”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
(gdb)

I read somewhere that this might be caused by a stack overflow? I'm lost...
 
First rule of debugging: Break it down.

There is a big difference between returning a constant and accessing an array to retrieve a value. You know what happens in the extremes: a fixed constant works, but the array reference and intValue doesn't. So figure out an intermediate point between those two extremes, and test that.

For example, get the object at the index, but return a constant instead of messaging it with intValue. Or confirm that the array is valid and has a non-zero length, but return a constant. Start simple, closer to the known-working "return a constant". Gradually add.


Second rule of debugging: Confirm that what you expect to happen is always what does happen.

Here, the expectation is that the section value passed to numberOfRowsInSection: is always a valid index for sectionNumberRows.

So instead of taking it on blind faith that sectionNumberRows always has the necessary number of elements, you could change numberOfRowsInSection: so if it's given a section parameter that's out of range for the current length of sectionNumberRows, it does something safe and informative, like NSLog() this fact, without attempting to access an invalid member of the NSArray.


Finally, is it running on the simulator or the device? Do both of them exhibit the same behavior?
 
Hi, thanks for the response.
I checked several things you mentioned before I posted, in fact I've been at this for around 6/7 hours now.

However based on what you said about trying all intermediate steps I tried using NSArrays in the methods instead of NSMutableArrays and they seems to work.

I simply copy the contents of the mutable array to the NSArray as follows

NSArray *aSectionTitles = [[NSArray alloc] initWithArray:sectionTitles];

I cant understand why the mutable arrays don't work in the stated methods when trying to access/manipulate the data in the arrays, but the exact same code using NSArrays does?
 
NSArray *aSectionTitles = [[NSArray alloc] initWithArray:sectionTitles];

Your NSArray is created using alloc, so you own it.
How is sectionTitles created, and do you own it?

In short, is the problem caused by arrays (or mutable arrays) being assigned to instance variables, but you've neglected to take ownership of them by retain?


And you didn't answer the question: Is it running on the simulator or the device?
 
Hi,

The code is running in the simulator (iPhone 4.0 with xcode 3.2.3). I haven't provisioned any device yet as I'm waiting to complete my app before joining the Apple dev program.

In the header file I have

NSMutableArray *sectionTitles;
NSArray *aSectionTitles;

I've only declared them as instance variables not with any retain statement.

Then in the implementation file I have
sectionTitles = [[NSMutableArray alloc] init];
declared within a method that populates the array thus
[sectionTitles addObject:aString];

If I try to use sectionTitles directly within the NSTableView delegate/dataSource methods the app crashes (although it may work 10% of the time - I think it is an out of memory issue).

However if I perform the copy
NSArray *aSectionTitles = [[NSArray alloc] initWithArray:sectionTitles];
after sectionTitles has been populated then aSectionTitles can be used successfully in the delegate/dataSource methods (works 100% of the time).

I'm confused as to why NSArray works but NSMutableArray causes crashes within the the delegate/dataSource methods?
 
IMPORTANT UPDATE!!!!

I added
@property (nonatomic, retain) NSMutableArray *sectionTitles;

and it is now working with the mutable array!!!

hmmmm, none of the examples I saw had a retain statement but it seems that this is necessary to ensure that they remain in the stack? I'm assuming they must have been getting kicked off the stack 90% of the time resulting in the silent crashes.

This was a valuable (if not painful) lesson learned - I was at this for hours last night. Any more funny behaviour related to memory I'll need to make sure that those variables are retained...

Thank you so much for your assistance chown33. I was rapidly going crazy :p
 
hmmmm, none of the examples I saw had a retain statement but it seems that this is necessary to ensure that they remain in the stack? I'm assuming they must have been getting kicked off the stack 90% of the time resulting in the silent crashes.
I think in your case, the more important aspect to consider is whether the objects added to the array were being retained or not.
 
I think in your case, the more important aspect to consider is whether the objects added to the array were being retained or not.

As I'm sure you know, objects added to an NSMutableArray are retained by that array. So unless those objects are being over-released somewhere else, they won't be released until the array holding them is dealloc'ed.


Code:
NSMutableArray *sectionTitles;
NSArray *aSectionTitles;
I've only declared them as instance variables not with any retain statement.

Then in the implementation file I have
Code:
sectionTitles = [[NSMutableArray alloc] init];
declared within a method that populates the array thus
Code:
[sectionTitles addObject:aString];
If I try to use sectionTitles directly within the NSTableView delegate/dataSource methods the app crashes (although it may work 10% of the time - I think it is an out of memory issue).
The sectionTitles ivar is being assigned an alloc'ed NSMutableArray reference. Therefore, unless something else is release'ing that array, then the creating object should own it.

Also, the array is being populated using an ivar reference form, not a property reference form, so there shouldn't be any unexpected releases during that.

Frankly, there just isn't enough posted code to tell anything about the context of how the variables are being used. Isolated lines of code are only meaningful if the cause of the error is in that specific code fragment. But given that you don't know the cause of the problem, it's unlikely that the fragments selected for posting will contain the cause, except by sheer luck. It's also possible that the direct cause is in a posted fragment, but a precipitating cause was not posted, and without that context, the posted code would look perfectly correct.

Posting complete methods and complete declarations would be an improvement over isolated fragments of code.


I added
@property (nonatomic, retain) NSMutableArray *sectionTitles;

and it is now working with the mutable array!!!
Given the code you've posted so far, I see no reason why declaring a nonatomic retained property would cause it to work, especially because none of the posted code even uses a property reference form: it's all ivar references. I can only guess that the real cause of the problem lies somewhere in the code you haven't posted.

Any more funny behaviour related to memory I'll need to make sure that those variables are retained...
Retain isn't a magic bullet. You should retain objects only when you don't already have ownership, and the object's lifetime needs to be guaranteed. Throwing retain around like it's a magic bug-fixer will only lead to memory leaks.
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

One of the best things you could do now is run your program under Instruments.app, and check for leaks. Also run it with zombies enabled. You can't do both at once, so it will take two runs.

I also recommend running the old crashing version under Instruments with zombies enabled. If an object is being dealloc'ed because of a failure to retain, zombies will show it.

Thereafter, you should run the program under Instruments at least once a week, with leaks and zombies, and fix any problems it finds. Trust me, it's a lot easier to deal with leaks and over-releases in the early stages of development. Also, it will get you familiar with Instruments when your program is simpler, which will be very helpful after the program grows.
 
As I'm sure you know, objects added to an NSMutableArray are retained by that array. So unless those objects are being over-released somewhere else, they won't be released until the array holding them is dealloc'ed.
Yeah, I guess that is what I was hinting at.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.