views:

146

answers:

2

Hi all,

I have a user class that I use throught the iphone application,this is the init and initWithUser fuctions from my user class (A SUBCLASS OF NSobject),. when I use the initWithUser function I get the warning described after the code. please advise.

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

@protocol Serialize

// serialize the object to an xml string
-(NSString*)ToXML;

@end


// user.h
#import <Foundation/Foundation.h>
#import "Serialize.h"
#import "Contact.h"


@interface User : NSObject <Serialize> {

NSString *email;
NSString *firstName;
NSString *lastName;
NSString *userId;
NSString *userName;
NSString *password;

NSMutableArray *contactList;

}

@property (nonatomic,copy) NSString *email;
@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;
@property (nonatomic,copy) NSString *userId;
@property (nonatomic,copy) NSString *userName;
@property (nonatomic,copy) NSString *password;
@property (nonatomic, retain) NSMutableArray *contactList;

//-(id)init;
-(id)initWithUser:(User *)copyUser;

@end



// user.m 
#import "user.h"


@implementation User

@synthesize email;
@synthesize firstName;
@synthesize lastName;
@synthesize userId;
@synthesize userName;
@synthesize password;
@synthesize contactList;

-(id)init
{
    // call init in parent and assign to self
    if( (self = [super init]) ) 
    {          
        // do something specific 
        contactList = [[NSMutableArray alloc] init];

    }
    return self;
}

-(id)initWithUser:(User *)copyUser
{
    if( (self = [self init]) ) {           

        email               = copyUser.email;
        firstName           = copyUser.firstName;
        lastName            = copyUser.lastName;
        userId              = copyUser.userId;
        userName            = copyUser.userName;
        password            = copyUser.password;

        // release contactList initialized in the init
        [contactList release];
        contactList         = [copyUser.contactList mutableCopy];
    }

    return self;
}

- (void)dealloc
{
    // TODO: 
    [contactList removeAllObjects];
    [contactList release];
    [super dealloc];
}

// implementation of serialize protocol
-(NSString*)ToXML
{
    return @""; 
}

and I use it in the main controller this way

- (void) registerNewUser {

    RegistrationViewController *regController = [[RegistrationViewController alloc] init] ;

    regController.newUser = [[User alloc] initWithUser:self.user];

    [self.navigationController pushViewController:regController animated:YES];
    [regController release];

}

the line

regController.newUser = [[User alloc] initWithUser:self.user];

gives me the following error, and its been driving me nuts for a couple of days:

incompatible Objective-c types 'struct User*', expected 'struct NSString *' when passing argument 1 of 'initWithUser:' from distinct Objective-c type

any help and guidance is appreciated

+5  A: 

The problem is you have an ambiguous selector. Because alloc returns id, the call to initWithUser: has become ambiguous. NSUserDefaults also has an initWithUser: function which takes a string. The compiler thinks you're trying to use that one. Change the line to

regController.newUser = [(User*)[User alloc] initWithUser:self.user];

and everything should work as expected.

Joshua Weinberg
thank you so much, I changed the name to initWithAUser to remove the ambiguity. I wouldnt have thought of that, you saved me a lot of frustration. and thank you all for helping out.
curiousMo
Good call. Seems to me that the compiler warning should be able to spell out that it's ambiguous, not that the argument is of the wrong type since there's no particular reason to prefer NSUserDefault over User.
imaginaryboy
I think Clang might have a better warning for this case. In a perfect world it would be able to see what type you're assigning to and pick the right selector that returns that type.
Joshua Weinberg
+1  A: 

As mentioned in the comments, there are other problems with your implementation. In your initializer, reusing the -init is redundant and the assignments to ivars like email should be taking ownership of the data using -copy or -retain:

-(id)initWithUser:(User *)copyUser {
    if((self = [super init])) {
        // take ownership of the users data by copying or retaining:
        email = [copyUser.email copy];
        // ...

        contactList = [copyUser.contactList mutableCopy];
    }    
    return self;
}

In -dealloc, -removeAllObjects can be removed and the member data has to be released:

- (void)dealloc {
    [email release];
    // ...

    [contactList release];
    [super dealloc];
}

Note that you are also leaking the new User instance if newUser is a copy or retain property as there is a release missing:

User *user = [[User alloc] initWithUser:self.user];
regController.newUser = user;
[user release];
Georg Fritzsche
thank you for taking the time to create this implementation.
curiousMo