views:

201

answers:

2

Hi there,

I'm pretty new in IPhone Development, so maybe you can help me with this problem:

I'm having an object "preferences" that holds a single NSString: (All code simplified...)

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>


@interface Preferences : NSObject {
 NSString *username;

}

-(void)loadPreferences;

@property(nonatomic,retain) NSString *username;

@end

The implementation looks like this:

#import "Preferences.h"
@implementation Preferenes

@synthesize username;

-(void)loadPreferences{
     username=@"MyUser";
}

-(void) dealloc {
 [username release];
}
@end

Next, I'm using a retain reference to this object in my main delegate:

#import <UIKit/UIKit.h>

@interface MainDelegate : NSObject <UIApplicationDelegate> {

   ...

  Preferences *prefs;
}

@property(retain,nonatomic) Preferences *prefs;

Implementation:

#import "MainDelegate.h"
#import "Preferences.h";

@implementation MainDelegate

@synthesize prefs;

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
     prefs=[[Preferences alloc] init];
     NSLog(@"Username: %@",prefs.username); // THIS WORKS 
}

So I can access prefs.username in the Main Delegate.

Now I want to access the preferences reference from my MainDelegate.

I'm trying to do this this way:

MainDelegate *delegate = (MainDelegate*) [[UIApplication sharedApplication] delegate];
Preferences *prefs=delegate.prefs;
// This works...

NSLog(@"The Username is: %@",prefs.username);
// CRASH

When I'm trying to access the "username" object within the preferences object, the programm crashes with only showing the GNU Licence Information.

I think there is something going wrong that maybe an object is already released when I try to access it...

Can you help me out ?

Thanks !

+1  A: 

You may have issues with assigning your property. This line does not use your property setter that handles retaining the value for you

username=@"MyUser";

You want to do:

self.username = @"MyUser";

Which actually compiles to

[self setUsername:@"MyUser"];

This calls the method created by @synthesize username; which retains that string for you. So what may be happening is you are assigning an autoreleased string to your variable, which gets released, and you later try and access it, and it explodes.

If you declare a property with retain then it's best to do your assigning and releasing most of the time through that synthesized property. It makes memory management much simpler.


This line, hoever, works fine:

prefs=[[Preferences alloc] init];

This is because you are directly setting the instance variable to an object with a retain count of 1, since it was just initialized. But I usually prefer to use the property setter to keep things clearer and more consistent.

self.prefs = [[[Preferences alloc] init] autorelease];

This init's it (+1) it's retained by the property setter (+1) and is autoreleased later (-1). Leaving a retain count of 1, which represents being owned by the app delegate object.

In my experience, using the retained property setters really helps keep memory management bugs down to a minimum.

Squeegy
I'm totally new to this, but the guys who wrote my book are not :) They say that you shouldn't use autorelease where's it's easy not to (memory constrained device). With a `[prefs retain]` after the alloc init and a `[prefs release]` on the `dealloc` override it would be fine. Please correct me if I'm wrong, as I would LOVE to autorelease everywhere if possible ON IPHONE.
Yar
There are a lot of opinions one way or the other. It is true that you can have finer control over memory with manual `retain`/`release`. You can make sure you keep objects around for the shortest amount of time possible, making more memory free more often. But in practice, most apps don't need this level of control. Unless you are actually pushing the memory limits of the device, autorelease is fine. And it's easy to simply let the retain/release for any given method to net a zero, which lets you easily find memory bugs in a small bits of code instead of throughout your entire class.
Squeegy
The other case where you may want to manually retain and release is when dealing with large objects that take up a lot of memory. For instance iterating through an array for images that are hundreds of kilobytes each. But again, for handfuls of smaller objects is simpler not to worry about.
Squeegy
A: 

Thank you so much !

When I use self.username=@"MyUser" everthing works perfect. I didn't realize that the property will be skipped without using the self.

Great help !!

Steblo
Please don't post replies as new answers. Just add a comment if you want to say thanks.
Felixyz
And accept the answer that was correct, of course :)
Squeegy