views:

64

answers:

4

Attempting to make a NSObject called 'Person' that will hold the login details for my application (nothing to fancy). The app is made of a navigation controller with multiple table views but I am having issues sharing the Person object around.

Attempted to create a static object like this:

+ (Person *)sharedInstance {
    static Person *sharedInstance;
    @synchronized(self) {
        if(!sharedInstance)
            sharedInstance = [[Person alloc] init];
        return sharedInstance;
    }
    return nil;
}

And here is the header

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

@interface Person : NSObject {

    NSString    *fullName;
    NSString    *firstName;
    NSString    *lastName;
    NSString    *mobileNumber;
    NSString    *userPassword;
}

@property(nonatomic, retain) NSString   *fullName;
@property(nonatomic, retain) NSString   *firstName;
@property(nonatomic, retain) NSString   *lastName;
@property(nonatomic, retain) NSString   *mobileNumber;
@property(nonatomic, retain) NSString   *userPassword;

+ (Person *)sharedInstance;
-(BOOL) setName:(NSString*) fname;
-(BOOL) setMob:(NSString*) mnum;
-(BOOL) setPass:(NSString*) pwd;

@end

This object setters and getters are needed in different parts of the application. I have been attempting to access them like this

Person * ThePerson = [[Person alloc] init];
ThePerson = nil;
NSString * PersonsName;
PersonsName = [[Person sharedInstance] firstName];

Everything works well at the login screen but it dies at the next use. usually EXC_BAD_ACCESS (eek!).

Clearly I am doing something very wrong here. Is there an easier way to share objects between different a number view controllers (both coded and xib)?

+2  A: 

Why not store this information in the NSUserDefaults or the Keychain?

St3fan
hehe, NSUserDefaults a one word answer. Why am I not using it, because I did not know.
oden
A: 

You're not using the shared instance pattern correctly. Your sharedInstance method should alloc and init a new Person (if it has not already been done once) and assign it to the sharedInstance static variable.

Then when you need a pointer to the person, you should use the shared instance class method, not alloc and init a new instance yourself.

Technically, if you're going for a full blown singleton, your alloc method shouldn't allow you create a new instance of a Person.

Also, I just re-read your code, and came across a bit of a WTF:

Person * ThePerson = [[Person alloc] init];
ThePerson = nil;

What is that all about? That's a memory leak, right there.

All your problems can be solved by replacing any and all lines of Person *thePerson = [[Person alloc] init]; with Person *person = [Person sharedInstance];

Jasarien
Good point. Shame it did not change anything, still dies each time on the second call.
oden
It probably has something to do with the fact that your static variable is being re-declared each time the sharedInstance method is called. Try moving it outside the @implementation block.Other than that, you're obviously not managing the memory properly. EXEC_BAD_ACCESS is almost always an over-release problem. You can debug this by enabling NSZombies, check out http://www.cocoadev.com/index.pl?DebuggingTechniques
Jasarien
Static variables are not redefined (declarations only happen once for any variable, by the way). Moving the variable definition wouldn't make any difference. Placing it inside the block only changes the scope, and in this case it's preferable to keep the scope limited.
jlehr
Oden, If you've modified the code you posted previously, it might be a good idea to post the current version. Also, posting entire methods instead of just snippets might help clarify things.
jlehr
A: 

Your init is hinky, if you want to set the firstName of Person do it like this

Person *thePerson = [Person sharedInstance];  
thePerson.name = @"John Public";

to get the name out,

NSString *personName = [[Person sharedInstance] name];  

That will work in any class that #imports "Person.h"

willc2
+1  A: 

Your +sharedInstance method returns nil when it should be returning the shared instance. Also, I doubt there's any value to synchronizing on that block. The method could be written more simply:

+ (Person *)sharedInstance {
    static Person *sharedInstance;
    if(!sharedInstance) {
        sharedInstance = [[Person alloc] init];
    }
    return sharedInstance;
}

Note that this does not create a 'static object', since there's no such thing in Objective-C; it just assigns an object to a static variable (probably what you meant, but just wanted to make sure).

Another way to share an object among two or more view controllers within a navigation controller is to add a property to the nested view controllers, and call the setter method before navigating. For example, you could add a property such as the following:

@property (nonatomic, retain) Book *book;

to a child of the root view controller, and send it a -setBook: message in the root view controller's -tableView:didSelectRowAtIndexPath: method.

jlehr
Changing sharedInstance in this way made no difference. Just before the return nil I added a NSLog to see if it was ever returning nil and it did not.
oden