2010-01-08 3 views
15

У меня есть простой вопрос о создании нескольких инициализаторов в классе object-c. В принципе у меня есть класс, который представляет одну строку в моей базе данных (пользователей). В настоящее время у меня есть инициализатор, который инициализирует класс на основе пользователя UserID (который также является первичным ключом в базе данных), при передаче UserID класс будет подключаться к веб-сервису, анализировать результаты и возвращать объект, инициализированный соответствующей строкой в базе данных.Objective-C Несколько инициализаторов

В этой базе данных есть несколько уникальных полей (имя пользователя и адрес электронной почты), я также хотел бы иметь возможность инициализировать мой объект на основе этих значений. Но я не уверен, как иметь несколько инициализаторов, все, что я прочитал, утверждает, что я свободен иметь несколько инициализаторов, если каждый вызывает назначенный инициализатор. Если бы кто-то мог мне помочь, это было бы здорово.

Мой инициализатора код выглядит следующим образом:

- (id) initWithUserID:(NSInteger) candidate { 
    self = [super init]; 
    if(self) { 
     // Load User Data Here 
     NSString *soapMessage = [NSString stringWithFormat: 
           @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 
           "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" 
           "<soap:Body>\n" 
           "<GetByUserID xmlns=\"http://tempuri.org/\">\n" 
           "<UserID>%d</UserID>\n" 
           "</GetByUserID>\n" 
           "</soap:Body>\n" 
           "</soap:Envelope>\n", candidate 
           ]; 
     NSLog(@"%@",soapMessage); 

     // Build Our Request 
     NSURL *url = [NSURL URLWithString:@"http://photoswapper.mick-walker.co.uk/UsersService.asmx"]; 
     NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url]; 
     NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]]; 

     [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; 
     [theRequest addValue: @"http://tempuri.org/GetByUserID" forHTTPHeaderField:@"SOAPAction"]; 
     [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"]; 
     [theRequest setHTTPMethod:@"POST"]; 
     [theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]]; 

     NSError *WSerror; 
     NSURLResponse *WSresponse; 

     webData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&WSresponse error:&WSerror]; 

     xmlParser = [[NSXMLParser alloc] initWithData: webData]; 
     [xmlParser setDelegate: self]; 
     [xmlParser setShouldResolveExternalEntities: YES]; 
     [xmlParser parse]; 
    } 
    return self; 
} 

Исходя из комментариев Лорана, я пытался реализовать свое собственное решение, я был бы признателен, если бы вы могли сообщить мне о каких-либо очевидных Гоча с этим решением:

Я не совсем уверен, что понимаю, что вы имеете в виду, я попытался реализовать свое собственное решение. Буду признателен, если вы могли бы дайте мне знать, что вы думаете:

- (id) init { 
    self = [super init]; 
    if(self){ 
     // For simplicity I am going to assume that the 3 possible 
     // initialation vectors are mutually exclusive. 
     // i.e if userName is used, then userID and emailAddress 
     // will always be nil 
     if(self.userName != nil){ 
      // Initialise object based on username 
     } 
     if(self.emailAddress != nil){ 
      // Initialise object based on emailAddress 
     } 
     if(self.userID != 0){ // UserID is an NSInteger Type 
      // Initialise object based on userID 
     } 
    } 
    return self; 
} 
- (id) initWithUserID:(NSInteger) candidate { 
    self.userID = candidate; 
    return [self init]; 
} 
- (id) initWithEmailAddress:(NSString *) candidate { 
    self.emailAddress = candidate; 
    return [self init]; 
} 
- (id) initWithUserName:(NSString *) candidate { 
    self.userName = candidate; 
    return [self init]; 
} 

С уважением

+2

ПРЕДУПРЕЖДЕНИЕ - вероятный отказ приложения: вам необходимо инициализировать себя, используя назначенный инициализатор, прежде чем вы установите self.userID или аналогичный. Это связано с тем, что 1) память объекта может быть перераспределена в новое место путем вызова [super init] в [self init], потеря вашего инициализированной переменной и 2) идентификатор пользователя может быть перезаписан вызовом [self init]. Сделайте это: if (self = [self init]) {self.userID = кандидат} return self; –

ответ

16

определение Назначенный Initializer является here. Это сильное требование обеспечить соответствие ваших экземпляров независимо от используемого вами инициализатора. Полную ссылку см. В разделе Objective-C Programming Guide: реализация инициализатора хорошо документирована.

Edit 2: Fix опечатка сообщает @NSResponder

Edit:

Я думаю, вызывая инициализации после установки элемента не является надежным. У членов могут быть странные значения, которые не пройдут проверку на инициализацию.

Лучший способ сделать это - сначала вызвать метод «init» (который будет устанавливать значения по умолчанию для членов), а затем установить его. Таким образом, вы имеете такую ​​же структуру кода для всех ваших инициализаторах:

- (id) init { 
    self = [super init]; 
    if(self){ 
     self.userID = 0; 
     self.userName = nil; 
     self.emailAddress = nil; 
    } 
    return self; 
} 

- (id) initWithUserID:(NSInteger) candidate { 
    self = [self init]; 
    if(self){ 
     self.userID = candidate; 
    } 
    return self; 
} 
+0

Я отредактировал свое оригинальное сообщение, не могли бы вы сообщить мне, что вы думаете об этом решении. Большое спасибо Mick –

+0

См. Мои изменения для другого предложения. –

+0

Могу ли я задать вопрос?Каков назначенный инициализатор в классе? Если класс подклассов, init не может быть назначенным инициализатором, который должен вызываться инициализатором подкласса, потому что в это время идентификатор пользователя, адрес электронной почты и имя пользователя еще не назначены. – yehnan

7

То, как я, как правило, делать такого рода вещи для назначенного инициализатор быть метод, который принимает большинство параметров, и простые Инициализаторы просто отправьте более подробные сообщения -init. Например:

// simple initializer 
- (id) init 
    { 
    return [self initWithWidth: 1.0]; 
    } 

    // not so simple initializer 
- (id) initWithWidth:(float) aWidth 
    { 
    return [self initWithWidth:aWidth andColor:nil]; 
    } 

    // designated initializer. This is the one that subclasses should override. 
- (id) initWithWidth: (float) aWidth andColor: (NSColor *) aColor 
    { 
    if (self = [super init]) 
    { 
    self.width = aWidth; 
    self.color = aColor ? aColor : [[self class] defaultColor]; 
    } 
    return self; 
    } 
Смежные вопросы