2013-08-12 29 views
6

Tôi đọc vài chủ đề khác về nó, nhưng tôi vẫn bị mất.Cách triển khai đúng cách mutableCopyWithZone và copyWithZone

Tôi muốn tạo 2 loại đối tượng, một đối tượng không thay đổi chỉ với thuộc tính "chỉ đọc" và một thuộc tính có thể thay đổi chỉ với thuộc tính "ghi đè".

Cho phép gọi chúng là EXCar và EXMutableCar.

EXCar là phân lớp của NSObject và EXMutableCar là phân lớp của EXCar.

ExCar sẽ có trong giao diện của nó

@property (nonatomic, strong, readonly) NSString *name; 

EXMutableCar sẽ có trong giao diện của nó

@property (nonatomic, strong) NSString *name; 

Vì vậy, tôi "mở" tính chất của EXCar khi tôi sử dụng subclasse nó EXMutableCar. Và sau đó nó có thể thay đổi. Vấn đề là sao chép chính xác giữa chúng.

tôi thực hiện mutableCopyWithZone trong EXCar:

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar *mutableCopy = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCopy.name = _name; 

    return mutableCopy; 
} 

Câu hỏi đầu tiên, nó là cách tốt để làm điều đó? (Tôi muốn nuốt bản sao)

Vấn đề là với copyWithZone. Kể từ khi các thuộc tính của EXCar là readonly tôi không thể tạo không phải trong EXCar, không phải trong EXMutableCar một trường hợp mới của EXCar và điền thuộc tính của nó như thế này:

- (id)copyWithZone:(NSZone *)zone { 
    EXCar *copy = [[EXCar allocWithZone:zone] init]; 
    copy.name = _name; // This can't work... 

    return copy; 
} 

Và tôi không thực sự muốn làm một "init" phương pháp với 15 thuộc tính để vượt qua (chắc chắn, EXCar là một ví dụ, các lớp thực sự có đầy đủ nhiều thuộc tính). Và thông thường chúng được bắt đầu từ thông điệp JSON từ máy chủ, vì vậy chúng không cần phương thức init phức tạp.

Câu hỏi thứ hai là như vậy, cách thực hiện copyWithZone khiến lớp học của tôi không thay đổi được?

Nhờ sự giúp đỡ của bạn :)

Trả lời

9

Code:

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

@interface EXCar : NSObject <NSCopying, NSMutableCopying> 

@property (nonatomic, strong, readonly) NSString* name; 

@end 

// EXCar.m 
#import "EXCar.h" 
#import "EXMutableCar.h" 

@implementation EXCar 

- (id)copyWithZone:(NSZone *)zone { 
    EXCar* car = [[[self class] allocWithZone:zone] init]; 
    car->_name = [_name copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* mutableCar = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCar.name = [_name mutableCopyWithZone:zone]; 
    return mutableCar; 
} 

@end 

// EXMutableCar.h 
#import "EXCar.h" 

@interface EXMutableCar : EXCar 

@property (nonatomic, strong) NSString* name; 

@end 

// EXMutableCar.m 
#import "EXMutableCar.h" 

@implementation EXMutableCar 

@synthesize name = _mutableName; 

- (id)copyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super copyWithZone:zone]; 
    car->_mutableName = [_mutableName copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super mutableCopyWithZone:zone]; 
    car->_mutableName = [_mutableName mutableCopyWithZone:zone]; 
    return car; 
} 

Giải thích:

  • EXCar giao diện thực hiện cả hai "sao chép" các giao thức;
  • Phân lớp EXMutableCar ghi đè cùng một thuộc tính, biến nó thành readwrite.

Điều đầu tiên trong EXMutableCar thực hiện: bằng tay @synthesize name vì Xcode cho chúng ta một lời cảnh báo, vì chúng ta có cùng một tài sản (nhưng với specifier truy cập khác nhau) trong lớp cha của chúng tôi.

Lưu ý chúng ta có thể đã được đặt tên tương tự để biến dụ của chúng tôi, như _name, nhưng điều quan trọng là phải hiểu rằng chúng ta khai báo trong lớp con một biến khác nhau, vì _name từ lớp cha là không thể tiếp cận đối với chúng tôi.

Tiếp theo, Apple bang tài liệu:

Nếu một lớp con thừa hưởng NSCopying từ lớp cha của nó và tuyên bố biến dụ bổ sung, lớp con có để ghi đè copyWithZone: để xử lý đúng đắn các biến dụ của riêng mình, gọi thực hiện của lớp cha đầu tiên.

tương tự cho NSMutableCopying:

Nếu một lớp con thừa hưởng NSMutableCopying từ lớp cha của nó và tuyên bố biến dụ bổ sung, lớp con có để ghi đè mutableCopyWithZone: để xử lý đúng đắn các biến dụ của riêng mình, gọi thực hiện của lớp cha đầu tiên.

Chúng tôi làm khai báo các biến mẫu bổ sung, vì vậy chúng tôi cũng ghi đè lên các phương thức này trong phân lớp của chúng tôi.

Kết quả:

EXCar* car = [[EXCar alloc]init]; // car.name is (null) 
EXCar* carCopy = [car copy]; // we can do this 
EXMutableCar* mutableCar = [car mutableCopy]; // and this 
mutableCar.name = @"BMW"; 
car = [mutableCar copy]; // car.name is now @"BMW" 
EXMutableCar* anotherMutableCar = [car mutableCopy]; //anotherMutableCar.name is @"BMW" 
+0

Sao chép trên lớp con có thể thay đổi phải trả lại phiên bản bất biến, ví dụ EXCar, không phải EXMutableCar. Điều này đặc biệt quan trọng nếu các lớp thực hiện bình đẳng tùy chỉnh khi hàm băm có thể phụ thuộc vào một số giá trị có thể thay đổi (trong phân lớp có thể thay đổi), đó là lý do tại sao, ví dụ, NSDictionary sao chép khóa của nó, nó mong đợi các đối tượng bất biến trở lại với băm không thay đổi. –

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