2010-01-08 9 views
15

Tôi có một câu hỏi đơn giản về việc tạo nhiều initialisers trong một lớp khách quan-c. Về cơ bản tôi có một lớp đại diện cho một hàng trong cơ sở dữ liệu của tôi (người dùng). Tôi hiện đang có một initialiser khởi tạo lớp dựa trên UserID người dùng (cũng là khóa chính trong cơ sở dữ liệu), khi đã thông qua UserID lớp họ sẽ kết nối với một webservice phân tích các kết quả và trả về một đối tượng được khởi tạo cho hàng tương ứng trong cơ sở dữ liệu.Mục tiêu-C Nhiều Initialisers

Trong cơ sở dữ liệu này là một số trường duy nhất (tên người dùng và địa chỉ email), tôi cũng muốn có thể khởi tạo đối tượng dựa trên các giá trị này. Nhưng tôi không chắc chắn làm thế nào để có nhiều hơn một initialiser, tất cả mọi thứ tôi đã đọc tiểu bang rằng tôi tự do để có nhiều initialisers, miễn là mỗi cuộc gọi initialiser được chỉ định. Nếu ai đó có thể giúp tôi với điều này, điều đó thật tuyệt.

đang initialiser của tôi là như sau:

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

Tiếp theo từ bình luận Laurent, tôi đã cố gắng để thực hiện giải pháp của riêng tôi, tôi sẽ rất biết ơn nếu bạn có thể thông báo cho tôi về bất kỳ của Gotcha rõ ràng với giải pháp này:

Tôi không hoàn toàn chắc chắn rằng tôi hiểu ý của bạn, tôi đã cố gắng thực hiện giải pháp của riêng mình. Tôi sẽ biết ơn nếu bạn có thể cho tôi biết những gì bạn nghĩ:

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

Trân

+2

CẢNH BÁO - lỗi ứng dụng có khả năng xảy ra: bạn cần phải tự khởi chạy bằng trình khởi tạo được chỉ định TRƯỚC KHI bạn đặt self.userID hoặc tương tự. Điều này là do 1) bộ nhớ đối tượng có thể được phân bổ lại đến vị trí mới bằng cách gọi tới [super init] trong [self init], mất biến khởi tạo của bạn và 2) userID có thể bị ghi đè bởi lệnh gọi tới [self init]. Làm điều này: if (self = [self init]) {self.userID = candidate} trả về tự; –

Trả lời

16

định nghĩa Các initializer định là here. Đó là một yêu cầu mạnh mẽ để đảm bảo rằng các cá thể của bạn nhất quán với bất kỳ trình khởi tạo nào bạn sử dụng. Để tham khảo đầy đủ, hãy xem Objective-C Programming Guide: việc triển khai trình khởi tạo được ghi lại đầy đủ.

Chỉnh sửa 2: Fix lỗi đánh máy báo cáo của @NSResponder

Edit:

Tôi nghĩ rằng gọi init sau khi cài đặt thành viên là không đáng tin cậy. Các thành viên có thể có các giá trị lạ sẽ thất bại trong việc thử nghiệm để khởi tạo.

Cách tốt nhất để thực hiện là gọi phương thức "init" trước (phương thức này sẽ đặt giá trị mặc định cho thành viên) và sau đó đặt thành viên. Bằng cách này, bạn có cấu trúc mã giống nhau cho tất cả initializers của bạn:

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

Tôi đã chỉnh sửa bài đăng gốc của mình, bạn có thể cho tôi biết suy nghĩ của bạn về giải pháp này không. Cảm ơn rất nhiều Mick –

+0

Xem chỉnh sửa của tôi cho đề xuất khác. –

+0

Tôi có thể đặt câu hỏi không?Trình khởi tạo được chỉ định trong lớp là gì? Nếu class được subclassed, init không thể là initializer được chỉ định mà nên được gọi bởi initializer của lớp con bởi vì tại thời điểm đó userID, emailAddress, và userName không được gán một giá trị trung bình nào được nêu ra. – yehnan

7

Con đường tôi có xu hướng làm điều này loại điều là cho initializer được chỉ định là phương pháp mà có các thông số nhất, và initializers đơn giản hơn chỉ cần gửi các thông điệp chi tiết hơn. Ví dụ:

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