0

I'm somewhat of a newbie to objective-c programming, and can't understand how to create a NSObject in one method and use it in another.

For example:

I have a UserObject with properties like firstName, lastName.

@interface UserObject : NSObject

@property (nonatomic, retain) NSString *userID, *firstName, *lastName, *profilePic, *fullName, *email, *twitter, *followingCount, *followerCount;

@end

In my profileViewController.h I declare currentUser as @property (retain, nonatomic) UserObject *currentUser;

Now, here's the problem. I have this IBAction

- (IBAction)followUser:(id)sender {
    NSLog(currentUser.firstName);
}

After receiving json data from a server, I run a method called ConnectionDidFinishLoading and inside ->

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [connection release];

    NSString *json = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    [responseData release];
    NSDictionary *dataArray = [json JSONValue];

    UserObject *currentUserData = [[UserObject alloc] init];
    currentUserData.firstName = [dataArray objectForKey:@"first_name"];
    currentUserData.lastName = [dataArray objectForKey:@"last_name"];

    currentUser = currentUserData;        

    [dataArray release];
    [json release];
    [currentUserData release];
}

Now, here's the problem. When I run this IBAction, the app crashes.

- (IBAction)followUser:(id)sender {
NSLog(@"%@",currentUser.firstName);
}

I'm pretty sure it's because the currentUser is not available to this method. Is there a way to make the currentUser object global so I can grab it in any method?

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
Brian Weinreich
  • 7,692
  • 8
  • 35
  • 59
  • The `followUser` action is in `ProfileViewController.m`, right? – Dr.Kameleon Apr 07 '12 at 17:54
  • yes its declared in .h as - (IBAction)followUser:(id)sender; and the action is in the .m file – Brian Weinreich Apr 07 '12 at 17:56
  • Well, I mean this `- (IBAction)followUser:(id)sender { NSLog(@"%@",currentUser.firstName); }` is in the `.m` file, right? – Dr.Kameleon Apr 07 '12 at 17:57
  • **Ideas/Questions :** 1) Is there a `@synthesize currentUser;` in your .m file? 2) Try declaring it as `@property (assign) userObject* currentUser` 3) Always GET its value with `[self currentUser]` and SET it with `[self setCurrentUser:whatever]`. – Dr.Kameleon Apr 07 '12 at 18:00
  • 1) Yes, there is a `@synthesize currentUser` in the .m file 2) It's assigned in the .h file as `@property (retain, nonatomic) UserObject *currentUser;` 3) I get currentUser = currentUserData; so that the object has the same values. – Brian Weinreich Apr 07 '12 at 18:03
  • @Chuck Good point. Now, as for 2)+3), please do try it; and let me know how it went. – Dr.Kameleon Apr 07 '12 at 18:04
  • No, not ARC since he's using `retain` instead of `strong` or `weak`. – lnafziger Apr 07 '12 at 18:29

3 Answers3

4

I think you're confused about the different between instance variables and properties. You're setting the currentUser instance variable directly, which does not retain the object — so assuming you're not using ARC, it'll get destroyed too early. You need to change the line where currentUser is set to one of these:

currentUser = [currentUserData retain];
// OR
self.currentUser = currentUserData;

The self.currentUser syntax is how you access the property. Without the dot, you're accessing the ivar directly.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • Perfect! Okay, I think I understand the difference now. So, I used self.currentUser = currentUserData in the connectionDidFinishLoading method and then in other methods I can access it via currentUser.firstName etc. Great! Thanks for the help everyone. Such a great community :) – Brian Weinreich Apr 07 '12 at 18:42
1

Try this :

NSLog(@"%@",currentUser.firstName);

Hint : %s is used for C-style strings.

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • Oops. Good catch. I meant to write that on here. That isn't the problem I'm running into. The problem (I believe) is that the currentUser is not available in that method. – Brian Weinreich Apr 07 '12 at 17:38
  • @BrianW Why don't you put a Breakpoint just before the `NSLog` line? Then you may see what's going on... – Dr.Kameleon Apr 07 '12 at 17:40
  • @BrianW You could also try changing `currentUser = currentUserData` to `[self setCurrentUser:[currentUserData retain]];` – Dr.Kameleon Apr 07 '12 at 17:43
  • Hmm.. I think I need to do more reading on Objective-C. I got this error, and am not sure. Thanks for your help. --[ProfileViewController currentUser:]: unrecognized selector sent to instance 0x6eaff80 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ProfileViewController currentUser:]: unrecognized selector sent to instance 0x6eaff80' – Brian Weinreich Apr 07 '12 at 17:46
  • @BrianW This usually means that it does NOT recognize `currentUser` as something that belongs to it (e.g. property or method). Could you please post EXACTLY the interface part of your `profileViewController`? Also, do you use `@synthesize` in the `.m` file for the property? – Dr.Kameleon Apr 07 '12 at 17:49
1

The problem is most likely that you are calling the followUser: method before any data is received from your server, so currentUser hasn't been created, so it is a null/dangling pointer, which is most likely crashing your app. Do a test to make sure currentUser isn't nil before using it:

if(currentUser) {
    //do what you want
    //if currentUser is nil, this if statement will evaluate to false
    NSLog(@"%@", currentUser.firstName);
}
eric.mitchell
  • 8,817
  • 12
  • 54
  • 92
  • Nope; now that I'm RE-thinking about it, it's not right. If it was nil, there would be no message like `unrecognized selector`... huh? – Dr.Kameleon Apr 07 '12 at 17:53
  • If the crash report says 'unrecognized selector', the problem might be that you changed the name of the IBAction without reconnecting it from Interface Builder. Trying breaking your Interface Builder outlets and reconnecting them. – eric.mitchell Apr 07 '12 at 17:59