2013-08-07 37 views
6

Tôi đang cố gắng hiểu cái nào nên được chỉ định khởi tạo và khởi tạo thuận tiện nào. Tôi đọc tài liệu về chủ đề đó nhưng tôi vẫn không chắc chắn. Trình khởi tạo được chỉ định có phải có tất cả các giá trị yêu cầu cho lớp không? Ví dụ
Đây là initializer định đầu tiên mà tôi tạo raTrình khởi tạo được chỉ định và khởi tạo thuận tiện trong mục tiêu-c và cách tạo chúng đúng cách và buộc chúng lại với nhau

-(id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck 
{ 
    self = [super init]; 
    if (self) { 
     for(int i = 0; i<=cardCount;i++){ 
      Card *card = [deck drawRandomCard]; 
      if (!card) { 
       self = nil; 
       break; 
      }else{ 
       self.cards[i] = card; 
      } 
     } 
    } 

    return self; 
} 

Bây giờ adde cardMatchMode tài sản cho lớp này và muốn cài đặt nó trong initializer. Để làm cho lớp tương thích ngược và để hiểu initializers tôi đang giữ một trong đó tôi có bây giờ và tạo một initializer.

-(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode 
{ 

    _cardMatchMode = matchMode; 
    return [self initWithCardCount:cardCount usingDeck:deck];; 
} 

Dựa trên các tài liệu táo initializer tiện phải trả về giá trị cho initializer định nhưng câu hỏi là tôi có thể thiết lập thuộc tính thêm vào lớp này trong initializer tiện lợi? Tôi có thể nói self.cardMatchMode = matchMode; hoặc bản thân vẫn chưa được khởi tạo đầy đủ không?
Nó không làm việc nhưng tôi chỉ muốn hiểu nếu điều này là mã đúng và tôi có thể truy cập vào các tài sản cardMatchMode trong init tiện hoặc tôi sẽ phải làm -(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode

như initializer định và init một tiện khác và làm lại mã? Cảm ơn!

///// Cập nhật

Tôi đã nhận được một lỗi trong

-(id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode 

Khi tôi đã cố gắng để làm self = [self initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck*)deck; lỗi nói rằng bạn không thể gán tự bên ngoài gia đình init. Tôi đã tìm ra vấn đề là gì. Phương thức init có chữ thường và nó phải là vốn nên giờ nó hoạt động. Đây là mã tôi có bây giờ cho initializer thuận tiện của tôi.

-(id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode 
{ 
    self = [self initWithCardCount:cardCount usingDeck:deck]; 
    if (self){ 
     _cardMatchMode = matchMode; 
    } 
    return self; 
} 

Bây giờ có ý nghĩa hơn. Tôi gọi là init được chỉ định gọi super và sau đó tôi đặt biến số cardMatchMode.

Theo tôi hiểu, có rất nhiều đối tượng có trình khởi tạo thuận tiện với các tham số bổ sung và nó sẽ chỉ là init được chỉ định của cuộc gọi. Nếu bạn nhìn vào NSString và nó có khởi tạo khác nhau với các tham số khác nhau. Nó có thể gọi init là bộ khởi tạo được chỉ định. Điều này có đúng không?

+0

Bạn đã nghe nói về constructor quá tải? Trình khởi tạo được chỉ định giống như trong Java với tư cách là hàm tạo thực, nó chiếm hầu hết các tham số. Sau đó, 'initializer' thuận tiện sẽ gọi khi' initializer' được chỉ định để thực hiện công việc, tức là gọi 'super init'. –

Trả lời

6

Theo Apple Tài liệu, các định initalizer

thường là init ...phương thức có nhiều tham số nhất và hầu hết công việc khởi tạo.

Vì vậy, trong trường hợp của bạn, đây sẽ là - (id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode. Tất cả các trình khởi tạo khác sẽ có ít đối số hơn, điền vào các tham số thiếu trên trình khởi tạo được chỉ định với các giá trị mặc định hoặc ngược lại.

Vì vậy, mỗi trình khởi tạo thuận tiện gọi bộ khởi tạo được chỉ định thay vì trình khởi tạo của lớp cha.

Thuận tiện-định cặp initializer sẽ trông như thế này trong trường hợp của bạn:

/** 
Convenience initializers 
*/ 
- (id)init 
{ 
    self = [self initwithCardCount:kDefaultCardCount usingDeck:[Deck defaultDeck] cardMatchMode:kCardMatchModeDefault]; 
    return self; 
} 

- (id)initWithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck 
{ 
    self = [self initwithCardCount:cardCount usingDeck:deck cardMatchMode:kCardMatchModeDefault]; 
    if (self) { 

    } 

    return self; 
} 

/** 
Designated initializer 
*/ 
- (id)initwithCardCount:(NSUInteger)cardCount usingDeck:(Deck *)deck cardMatchMode:(NSUInteger)matchMode 
{ 
    self = [super init]; 
    if (self) { 
     for (int i = 0; i <= cardCount; i++) { 
      Card *card = [deck drawRandomCard]; 
      if (!card) { 
       self = nil; 
       break; 
      } 
      else { 
       self.cards[i] = card; 
      } 
     } 
     // Set card match mode here: 
     _cardMatchMode = matchMode; 
    } 

    return self; 
} 
+1

Cảm ơn bạn đã trả lời. Kiểm tra câu trả lời cập nhật của tôi. Trong trường hợp này tôi thực sự không muốn mọi người gọi init bởi vì tôi muốn chắc chắn rằng họ vượt qua các tham số khi khởi tạo lớp này. Sẽ không có thông số mặc định. Về lâu dài tôi đoán nó không quan trọng bao nhiêu tham số được chỉ định và thuận tiện init có miễn là chỉ định sẽ gọi siêu và tiện lợi sẽ gọi được chỉ định. – Yan

15

Trình khởi tạo được chỉ định là trình khởi tạo trình khởi tạo được chỉ định của lớp cha của lớp, vì vậy nó là trình khởi tạo duy nhất gọi phương thức trên đối tượng super. Không có bộ khởi tạo nào khác trong lớp nên làm điều đó; các trình khởi tạo phụ này sẽ gọi trình khởi tạo được chỉ định sử dụng self. Thông thường, initializer được chỉ định có tất cả các tham số cần thiết để tạo ra một đối tượng hữu ích của lớp.

Tóm lại, trình khởi tạo được chỉ định là trình khởi tạo duy nhất gọi bộ khởi tạo trên super và tất cả các trình khởi tạo khác trong lớp gọi trình khởi tạo được chỉ định (sử dụng self).

+0

Cảm ơn bạn đã trả lời. Tôi cập nhật cái nào có ý nghĩa hơn bây giờ. Như những gì tôi hiểu miễn là chỉ initializer được chỉ định cuộc gọi siêu và thứ cấp chỉ cần gọi init được chỉ định mà nên làm việc. Tất cả các thuộc tính của lớp sẽ được khởi tạo bằng cách gọi đầu tiên được chỉ định sau đó đặt phần còn lại trong phần thứ hai. – Yan

Các vấn đề liên quan