Return object crashing iPhone - iphone

Im fairly new to the whole world of iPhone dev so forgive me if this is very easy. I have an object Card that holds 6 Question objects on it. when I say [card getQuestion:#"Art"] I am currently returning a Question object like so
- (Question*) getQuestion: (NSString*) questionType {
Question *q = [questions objectForKey:questionType];
return [q autorelease];
}
Question has a property of text (type NSString) which allows me to see what the text for the question is. So I want to use this text to update a UILabel in the viewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"%#", [[self.card getQuestion:#"Art"] qText]);
self.myQuestion.text = [[self.card getQuestion:#"Art"] qText];
}
This crashes the iPhone, whereas if I change the function in object Card to this
- (NSString*) getQuestion: (NSString*) questionType {
return [[questions objectForKey:questionType] qText];
}
and my call in the viewController to
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"%#", [self.card getQuestion:#"Art"]);
self.myQuestion.text = [self.card getQuestion:#"Art"];
}
This works fine.. can anyone explain what I am doing wrong, in both cases the call to NSLog returns me the relevant text. In both cases the display loads but in the first instance it crashes shortly after, whereas the other way it stays stable.
Any help appreciated.

- (Question*) getQuestion: (NSString*) questionType {
Question *q = [questions objectForKey:questionType];
return [q autorelease];
}
According to the memory management rules, you should not be autoreleasing that object, and this is almost certainly what is causing your crash. You're relinquishing ownership of an object you don't own, which is causing it to get deallocate prematurely. This means that when another object which is supposed to own the Question tries to access it, the Question is gone and you crash with an EXC_BAD_ACCESS error.
Additionally, the method should probably be called questionForType: or questionOfType:. Using the get prefix implies that the object will be returned via an out-parameter, which it's not.

Since you are new at all of this - you should definitely make sure you run your app looking for zombies and also run it with the instruments application to make sure you are not leaking anywhere.
You should read a very short explanation of memory mangement in Objective - C every few days - one day it will all sink in and become second nature.
http://macdevelopertips.com/objective-c/objective-c-memory-management.html

I can see two errors,
1: You are releasing something you don't own (Question 'q') - If you do either alloc, copy or retain, you should release it. If not, you shouldn't.
2: The setter-line should be written like this:
Question *q = (Question *)[questions objectForKey:questionType];
That way you avoid getting warnings or errors.

Related

Improvements on a beginner iOS application

I recently started out with iOS programming (with the Stanford CS193P lectures from iTunes U). I got stuck with the homeworks, that dreaded calculator is a bit too hard for me at the moment, so I started writing little, extremely simple applications to get used to the syntax and data structures in Objective-C.
I wrote a small application which has two buttons.. One 'initializes' an array and fills two UILabels with a) the first object (objectAtIndex:0) and b) the count. I then have a button which allows me to cycle through the array.. showing the next object in there when I click, and of course going back to the very first when I reach the end of the array.
This is easy. I know. But alas, I don't get any feedback like a real Stanford student would, and reading books don't really make me feel okay either. So I would like to ask for some feedback and possible code-improvements, best practices, etc. here.
I created a model with one method, which creates a list of items. I then send retain to it, because I was getting EXC_BAD_ACCESS problems without it; so here my first question: is this okay? :) I didn't think I had to retain it at first, and I still don't exactly understand why it works when I do in fact retain it. Or would it be better to somehow return this and 'catch' it in the controller? I really am not sure what the 'good' way is here.
-(void)populateItemsList
{
itemsList = [NSArray arrayWithObjects:#"Test", #"Test2", #"test3", nil];
[itemsList retain];
}
On to the next piece of code in my Controller:
I lazily instantiate my model here, because I learnt how to do this from the Stanford Calculator assignment. I suppose this is okay to do? I understand that this way, the memory for the model doesn't come in use until it's actually required?
- (DisplayerModel *)model
{
if(!displayerModel)
{
displayerModel = [[DisplayerModel alloc] init];
}
return displayerModel;
}
I then have a method to 'create' the array and populate my outlets (two UILabels, as mentioned before).
- (IBAction)createArray:(UIButton *)sender
{
[[self model] populateItemsList];
arrayCount = [[[self model] itemsList] count];
stepper = 0;
NSString *firstObject = [[[self model] itemsList] objectAtIndex:stepper];
countDisplay.text = [NSString stringWithFormat:#"%d", arrayCount];
display.text = [NSString stringWithFormat:#"%#", firstObject];
}
I'm honestly not sure about this code. It might just be me though, because I'm not really used to writing code in Objective-C; are there any improvements I could make here? I'm especially concerned about the whole stepper idea. I was looking for something like currentIndex or similar, but I couldn't seem to find it in the documentation.. that's why I created the stepper variable to keep track of where I am in the array.
And then finally, the method that makes me cycle through:
- (IBAction)showNextValue:(UIButton *)sender
{
if (stepper == arrayCount - 1) {
stepper = 0;
}
else {
stepper ++;
}
display.text = [NSString stringWithFormat:#"%#", [[[self model] itemsList] objectAtIndex:stepper]];
}
I'm not putting my dealloc or viewDidUnload overrides here because well.. I tested this application with Leaks and it doesn't seem to leak any memory. Are there other ways to test this? Build and analyze doesn't report any problems either. Are there other pitfalls I have to look out for?
Thanks to anyone who's willing to look through my code and provide me with some advice, etc. Still learning!
By convention, class methods using the class name at the beginning return an autoreleased object. Whereas, alloc/init or new return an object with a single retain count.
Thus:
foo = [[NSArray array] retain];
foo = [[NSArray alloc] init];
foo = [NSArray new];
are all equivalent and create an object (an empty array) with a retain count of 1
Lazy creation of needed objects is generally a good practice. It's also good to release those things in a variety of situations, viewDidUnload and memory warnings are two common places for that. If you do that, you might want to save the state in some way - often NSUserDefaults.
The stepper variable is perfectly fine. You could encapsulate it within your model if you wanted to. But in the controller is an acceptable location as well.
Looks pretty good. NSArray doesn't have anything like a currentIndex. An array just contains elements. The same array can be referenced by many objects. If two objects x and y use an array a, a can't keep track of currentIndex for users x and y separately. It's the responsibility of x and y to have its own stepper, as you did.

memory leak when adding objects to nsarray

In the code below, PersonListArray is an NSMutableArray and I'm getting the list of persons from the sqlite DB and adding it to my array.
Person* tmpPerson = [[Person alloc] init];
tmpPerson.personName = #"Mike";
tmpPerson.personEmail = #"mike#mike.com";
[PersonListArray addObject:tmpPerson];
[tmpPerson release];
Even though I'm releasing the Person object here, its giving a memory leak which I'm guessing is due to the array holding a reference count to it. I'm using the array elsewhere in the program and then releasing it for sure.
What's the best practice to create new objects for an array and not run into this issue?
In the dealloc method where i release the array
-(void) dealloc{
[PersonListArray release]; // this contains the numerous Person objects
[super dealloc];
}
should i manually release them like this instead ?
-(void) dealloc{
for (int i = 0; i<PersonListArray.count;i++)
{
Person * tmpPerson = [PersonListArray objectAtIndex:i];
[tmpPerson release];
}
[PersonListArray release];
[super dealloc];
}
The code you are showing us is correct and contains no leaks. The last section is wrong, though, and would case your program to crash because you are releasing Person objects you no longer own.
Your code, as initially implemented, is correct. An array retains onjects added to it and releases them either when they're removed from the array or when the array is dealloced. No need to go through the array yourself.
What means are you using to detect the leak? If it's Instruments then you may be misunderstanding what it is telling you. When it detects a leak, it can show you where the memory was first allocated. It can't show you which object is responsible for the leak. I would therefore guess the given dealloc method is never called (because that object is leaked) or that someone else retains the array and doesn't release it. Try putting an NSLog in dealloc to ensure that it is occurring; as a run once test you could try logging PersonListArray after releasing it — if that doesn't cause a memory exception then almost certainly someone else has retained it.
[REMOVED: my original text "Try adding an NSLog of [PersonListArray retainCount] to your dealloc to figure out which is the case."; see comment from bbum below]
The most common cause of accidental additional retains is #property/#sythesize properties that are set to retain but for which a matching release is not added to dealloc.
Somewhere else in your app, you probably call [PersonListArray objectAtIndex:n] and pass it around to various other parts of your app. One of the other parts of your app is probably leaking it.
If you're using leaks, click on the particular "type of leak", then click on the memory address, and it'll show you the alloc/free/retain/release/autorelease history of that memory address. If you enable the detail view (Cmd-E I think), you'll see stack traces for all of those as well. Look for something that's doing a retain but not a corresponding release. (It's a bit difficult when things are retained by multiple autoreleased arrays...)

NSMutable Array and brain damage

I have understandably attracted some smart ass answers to some bone head questions I have asked lately due to my complete misunderstanding of obj c and NSMutable arrays. So I've looked in a book I have and Google and it would appear that may be I shouldn't program because I'm still stuck.
Say I'm looping through method A and each loop through I want to add a double into a NSMutable array. This is what I've discovered so far.
You can't put primitives in arrays, so I made my double into a NSNumber object
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
XCode warns: 'NSNumber' may not respond to '+initWithDouble:'
and when I compile it get:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSNumber initWithDouble:]: unrecognized selector sent to class 0x1ffea0'
I ignore that and forge on. Some one told me I need an init method for the array, which makes sense because I don't want that happening in the loop. This is my init method:
-(id) init{
[super init];
arrayOfTouches = [[NSMutableArray alloc] init];
return self;
}
I haven't got to try to add it to the array yet.
[arrayOfTouches addObject:newObject];
Will this work to print out the array.
NSLog(#"array: %#", touchBeginObj);
Bonehead questions, probably. But damn if I can find anything that has all the pieces about what you can and can't do with an good example.
Thanks for any help or smart ass comments.
Yes, I have a Obj-C book, 3 actually and yes I'm reading them :)
Have a good weekend.
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
You’re missing the +alloc call in the above code, which is why it’s throwing that error—but why not just use:
NSNumber *newObject = [NSNumber numberWithDouble:doubleNumber];
It’s autoreleased, so you don’t have to worry about releasing it later.
I’m not sure what either of the other questions are asking, could you possibly rephrase them? From the code you’ve given, I think it should work
First :
[NSNumber numberWithDouble: double]
instead of
[NSNumber initWithDouble: double]
Your addObject looks fine.
You have several ways to print your array, I'd suggest iterating, as it will be useful later:
for (NSNumber *number in arrayOfTouches)
{
NSLog(#"Number %f", [number doubleValue]);
}
initWithDouble is an instance method, you're looking for the class method numberWithDouble.
Change this:
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
to this:
NSNumber *newObject = [NSNumber numberWithDouble:doubleNumber];
-initWithDouble is an instance method of NSNumber (so you would need to do [NSNumber alloc] first). +numberWithDouble is a class method.
You need to have zero warnings from the compiler - you can't ignore them and 'forge on'.
You are struggling with the basics, do you have experience of other programming languages?
There are a few things you must know in order to code in Objective-c and you must be familiar with the general concepts of object-oriented programming. Also a little C can be helpful as objective-c is an extension to C and it can give some perspective as to why object orientation is so useful and worth-the-effort.
If you already know a language like Python, Java, or even Actionscript then pretty much all of the concepts are the same and objective-c really isn't that difficult. You just need the specifics on how those concepts translate into objective-c. For example,
How do you define a class? How do you override an existing class? What does an initializer method look like? How do you create an instance of a class? etc. There are a few more things than this, but really not that many - you need to learn them, or at least have references at hand in the beginning so you don't go wrong. If you don't know what they mean then you need to learn that.
A 'Class' is like a blueprint for the layout of a piece of memory, in the case of NSNumber a piece of memory that we would hope is going to hold a number. The NSNumber Class knows how big the memory has to be and how it should be laid out. We really care little about the blueprint, the Class - we want an actual chunk of memory that can hold a number - an instance of the Class.
In objective-c creating an object, an instance, of a given class always, everytime, always, always involves -- firstly -- claiming ownership of a free chunk of memory with the correct size, saving the address of that chunk of memory to a variable, then giving the object a chance to do it's own initial setup by calling it's preferred setup method.
To claim ownership of the memory you send the alloc method to the class.
NSNumber *myNumberVariable = [NSNumber alloc];
To set the number up with the initial value of 10.0 you send the message initWithDouble: to your new instance.
[myNumberVariable initWithDouble:10.0];
For convenience these can be, and usually are combined into one statement.
NSNumber *myNumberVariable = [[NSNumber alloc] initWithDouble:10.0];
This is the most fundamental aspect of objective-c programming. You cannot do anything without thoroughly understanding this. Googling init objective-c returns literally hundreds of tutorials, guides, cheat-sheets and help.
If your own Class needs a property initializing when an instance is created, like your arrayOfTouches, you must override the preferred setup method of the parent Class. If the parent Class is NSObject, NSObject's preferred setup method is init. If you create an object in your setup method you must always have a dealloc method. This will always, always, all of the time look like this:
- (id)init {
self = [super init];
if(self){
}
return self;
}
- (void)dealloc {
[super dealloc];
}
Only the name "init" will change, depending on the name of the method you are overriding, - (id)init becomes - (id)nameOfMethodIAmOverriding and [super init] becomes [super nameOfMethodIAmOverriding];
Given this standard template for setup and teardown you can add in the setup and teardown of your own properties. In your case giving you.
- (id)init {
self = [super init];
if(self){
arrayOfTouches = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[arrayOfTouches release];
[super dealloc];
}
Look, it's not that i think you have Boneheaded questions, they are sensible questions but if you have 3 books - the answers are almost certainly on the first few pages of each book - maybe you are going about learning this wrong. Somehow you are not getting the fundamentals. The best i can suggest is to go more slowly and do the exercises in the book, Or choose a simpler language and attempt to master that before moving to objective-c.
Go to Help-->Developer Documentation
Search for NSNumber. Under class methods you'll find how to create a NSNumber with a double.

Why am i getting a EXC_BAD_ACCES

Hey. I have been working on a Twitter application and have been stuck on a EXC_ BAD_ ACCESS error for quite some time. I know that EXC_ BAD_ ACCESS is a memory issue but i cannot pinpoint where the problem is. Here is my code sample:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = #"/Volumes/Schools/BHS/Student/740827/Documents/Forrest McIntyre CS193P/Presence2";
NSArray *propList = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:#"TwitterUsers" ofType:#"plist" inDirectory:path]];
people = [[NSMutableArray alloc]init];
for (NSString *name in propList) {
Person *p = [[Person alloc] initWithUserName: name];
[people addObject: p];
[p release];
}
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
The exception is thrown on the last brace after the comment. I believe that it is truly thrown in the for loop somewhere but just shows up upon exiting.
Here is the implementation file for Person:
#implementation Person
#synthesize image;
#synthesize username;
#synthesize displayName;
#synthesize statusArray;
-(id)initWithUserName:(NSString *)userName {
if(self = [super init])
{
self.username = userName;
NSDictionary *info = [TwitterHelper fetchInfoForUsername:userName];
self.displayName = [info objectForKey:#"name"];
NSLog([NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]]);
NSString *imageURL2 = [NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]];
self.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL2]]];
[info release];
self.statusArray = [TwitterHelper fetchTimelineForUsername:userName];
}
return self;
}
#end
Thanks for any help
EDIT: Here is the header file for PersonListViewController (the class that contains the ViewDidLoad).
This is just to show you where people is coming from.
#interface PersonListViewController : UITableViewController {
NSMutableArray *people;
}
#end
since you never retain propList or path you shouldn't be releasing them.
You should, however, release people
For an overview of memory management, see the Memory Management Programming Guide
For quick fixes, try the static analyzer.
I think the problem is here:
[propList release];
Since you created propList using arrayWithContentsOfFile you don't need to release it - it will be automatically released. The autorelease is actually what's causing the error since it is trying to release something that you already released manually.
ETA: as cobbal mentioned, you also don't need to release path.
Debugging EXC_BAD_ACCESS is difficult to debug. This happens when a message is sent to an object that is already released. You need to find out what is causing this generic error by turning on NSZombiEnabled environment variable so the Objective-C environment will be able to 'track' a deallocated object. Using this, when you get the error you can determine where the error occurred by looking at the call stack. You won't know where it is released but at least it will get you close.
I don't have it setup here, but you may also be passing a pointer to the error which will cause the object to not persist as a zombie/dummy.
Bottom line, you need to make sure the variables you are meaning to release, that you retain them as necessary.
This Technical Q&A by Apple gives tips on Finding bugs with EXC_BAD_ACCESS.
For one, neither of these are necessary in your example:
[path release];
[propList release];
because:
path is a string literal (will always exist)
propList is autoreleased
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
http://www.cocoadev.com/index.pl?NSZombieEnabled can be useful in tracking down EXC_BAD_ACCESS bugs. Instead of deallocating objects when they are released it puts them into a zombie state that raises an exception when they are subsequently accessed. Just be sure not to ever release code with this flag set, as it will leak memory like a sieve.
what is self.editButtonItem? I don't see it in your .h file
A couple of things.
In initWithUserName: you're getting info from a method that doesn't contain alloc/copy/create. Further, you don't explicitly retain it. Yet you release it. This is problematic assuming fetchInfoForUsername: autoreleases its result as expected according to the Cocoa Memory management rules.
Using property accessors in initializers is considered bad form since it can cause KVO notifications to be sent out for a half-baked instance.

Why should a self-implemented getter retain and autorelease the returned object?

Example:
- (NSString*) title {
return [[title retain] autorelease];
}
The setter actually retained it already, right? and actually nobody should bypass the Setter... so I wonder why the getter not just returns the object? It's actually retained already. Or would this just be needed in case that in the mean time another objects gets passed to the setter?
From here http://www.macosxguru.net/article.php?story=20030713184140267
- (id)getMyInstance
{
return myInstanceVar ;
}
or
- (id)getMyInstance
{
return [[myInstanceVar retain] autorelease] ;
}
What's the difference ?
The second one allows the caller to get an instance variable of a container object, dispose of the container and continue to play with the instance variable until the next release of the current autoreleased pool, without being hurt by the release of the instance variable indirectly generated by the release of its container:
aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
If the "get" is implemented in the first form, you should write:
aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
The first form is a little bit more efficent in term of code execution speed.
However, if you are writing frameworks to be used by others, maybe the second version should be recommanded: it makes life a little bit easier to people using your framework: they don't have to think too much about what they are doing…;)
If you choose the first style version, state it clearly in your documentation… Whatever way you will be choosing, remember that changing from version 1 to version 2 is save for client code, when going back from version 2 to version 1 will break existing client code…
It's not just for cases where someone releases the container, since in that case it's more obvious that they should retain the object themselves. Consider this code:
NSString* newValue = #"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
This looks reasonable, but if neither the setter nor the getter uses autorelease the "Go on to do something" part will likely crash, because oldValue has now been deallocated (assuming nobody else had retained it). You usually want to use Technique 1 or Technique 2 from Apple's accessor method examples so code like the above will work as most people will expect.
Compare this code
return [[title retain] release]; // releases immediately
with this
return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
The second one guarantees that a client will have a non-dealloced object to work with.
This can be useful in a situation like this (client code):
NSString *thing = [obj title];
[obj setTitle:nil]; // here you could hit retainCount 0!
NSLog(#"Length %d", [thing length]); // here thing might be dealloced already!
The retain (and use of autorelease instead of release) in your title method prevents this code from blowing up. The autoreleased object will not have its release method called until AFTER the current call stack is done executing (end of the current run loop). This gives all client code in the call stack a chance to use this object without worrying about it getting dealloc'ed.
The Important Thing To Remember: This ain't Java, Ruby or PHP. Just because you have a reference to an object in yer [sic] variable does NOT ensure that you won't get it dealloc'ed from under you. You have to retain it, but then you'd have to remember to release it. Autorelease lets you avoid this. You should always use autorelease unless you're dealing with properties or loops with many iterations (and probably not even then unless a problem occurs).
I haven't seen this pattern before, but it seems fairly pointless to me. I guess the intent is to keep the returned value safe if the client code calls "release" on the parent object. It doesn't really hurt anything, but I doubt that situation comes up all that often in well-designed libraries.
Ah, ok. from the documentation smorgan linked to, it seems this is now one of the methods that Apple is currently recommending that people use. I think I still prefer the old-school version:
- (NSString *) value
{
return myValue;
}
- (void) setValue: (NSString *) newValue
{
if (newValue != myValue)
{
[myValue autorelease]; // actually, I nearly always use 'release' here
myValue = [newValue retain];
}
}