2010-01-08 17 views
15

Mam proste pytanie dotyczące tworzenia wielu inicjalizatorów w ramach klasy obiektu c. Zasadniczo mam klasy, która reprezentuje jeden wiersz w mojej bazie danych (użytkowników). Obecnie mam inicjalizator, który inicjuje klasę na podstawie UserIDu użytkownika (który jest także kluczem podstawowym w bazie danych), po przekazaniu identyfikatora UserID klasa połączy się z usługą internetową i przeanalizuje wyniki i zwróci obiekt zainicjalizowany do odpowiedniego wiersza w bazie danych.Wiele inicjalizatorów Objective-C

W tej bazie danych znajduje się szereg unikalnych pól (nazwa użytkownika i adres e-mail), chciałbym również móc zainicjować mój obiekt na podstawie tych wartości. Ale nie jestem pewien jak mieć więcej niż jeden inicjator, wszystko, co przeczytałem, stwierdza, że ​​mogę mieć wiele inicjalizatorów, o ile każdy wywoła wyznaczonego inicjatora. Gdyby ktoś mógł mi w tym pomóc, byłoby wspaniale.

Mój kod initialiser jest następujący:

- (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; 
} 

obserwuję z komentarzem Laurent, starałem się wdrożyć własne rozwiązanie, byłbym wdzięczny, gdyby mógł Pan poinformować mnie o wszelkich oczywistych haczyka jest z tego rozwiązania:

Nie jestem całkowicie pewien, że rozumiem, że masz na myśli, że próbowałem wdrożyć własne rozwiązanie. Byłbym wdzięczny, gdyby mógł Pan dać mi znać, co myślisz:

- (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]; 
} 

Pozdrowienia

+2

OSTRZEŻENIE - prawdopodobna awaria aplikacji: należy zainicjować samodzielnie przy użyciu określonego inicjalizatora PRZED ustawieniem self.userID lub podobnym. Dzieje się tak, ponieważ 1) pamięć obiektu może zostać ponownie przydzielona do nowej lokalizacji przez wywołanie [super init] w [self init], utrata zainicjowanej zmiennej i 2) userID może zostać nadpisane przez wywołanie [self init]. Zrób to: if (self = [self init]) {self.userID = kandydat} return self; –

Odpowiedz

16

definicja wyznaczonego inicjująca jest here. Jest to silny wymóg, aby upewnić się, że twoje wystąpienia są spójne, niezależnie od używanego inicjalizatora. Pełne informacje można znaleźć w dokumencie Objective-C Programming Guide: implementacja inicjalizatora jest dobrze udokumentowana.

Edit 2: Fix typo donosi @NSResponder

EDIT:

myślę wywołanie metody init po ustawieniu elementu nie jest niezawodny. Członkowie mogą mieć dziwne wartości, które zawiedzie test do inicjalizacji.

Lepszym sposobem jest wywołanie najpierw metody "init" (która ustawi domyślne wartości dla członków), a następnie ustawienie członka. W ten sposób można mieć taką samą strukturę kodu dla wszystkich inicjalizatorów:

- (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

Edytowałem mój oryginalny wpis, czy mógłbyś powiedzieć mi, co myślisz o tym rozwiązaniu. Bardzo dziękuję Mick –

+0

Zobacz moją edycję innej propozycji. –

+0

Czy mogę zadać pytanie?Jaki jest wskazany inicjator w klasie? Jeśli klasa jest podklasowana, init nie może być wyznaczonym inicjatorem, który powinien zostać wywołany przez inicjalizator podklasy, ponieważ w tym czasie ID użytkownika, adres e-mail i nazwa użytkownika nie mają jeszcze znaczącej wartości. – yehnan

7

Sposób staram się robić tego typu rzeczy jest wyznaczony initializer być metoda, która zajmuje najwięcej parametrów i prostsze inicjalizatory po prostu wyślij bardziej szczegółowe wiadomości -init. Na przykład:

// 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; 
    }