2012-03-28 34 views
73

Tôi cố gắng để làm sáng tỏ một vài điều trong đầu của tôi về việc thực hiện copyWithZone:, bất cứ ai có thể nhận xét về sau ...Thực hành tốt nhất copyWithZone khi thực hiện:

// 001: Crime is a subclass of NSObject. 
- (id)copyWithZone:(NSZone *)zone { 
    Crime *newCrime = [[[self class] allocWithZone:zone] init]; 
    if(newCrime) { 
     [newCrime setMonth:[self month]]; 
     [newCrime setCategory:[self category]]; 
     [newCrime setCoordinate:[self coordinate]]; 
     [newCrime setLocationName:[self locationName]]; 
     [newCrime setTitle:[self title]]; 
     [newCrime setSubtitle:[self subtitle]]; 
    } 
    return newCrime; 
} 

// 002: Crime is not a subclass of NSObject. 
- (id)copyWithZone:(NSZone *)zone { 
    Crime *newCrime = [super copyWithZone:zone]; 
    [newCrime setMonth:[self month]]; 
    [newCrime setCategory:[self category]]; 
    [newCrime setCoordinate:[self coordinate]]; 
    [newCrime setLocationName:[self locationName]]; 
    [newCrime setTitle:[self title]]; 
    [newCrime setSubtitle:[self subtitle]]; 
    return newCrime; 
} 

Trong 001:

  1. Tốt nhất là viết tên lớp học trực tiếp [[Crime allocWithZone:zone] init] hoặc tôi nên sử dụng [[[self Class] allocWithZone:zone] init]?

  2. Có thể sử dụng [self month] để sao chép iVars hoặc tôi có nên truy cập trực tiếp vào iVars tức là _month không?

Trả lời

94
  1. Bạn luôn nên sử dụng [[self class] allocWithZone:zone] để chắc chắn rằng bạn đang tạo ra một bản sao bằng cách sử dụng lớp thích hợp. Ví dụ bạn đưa ra cho 002 cho thấy chính xác lý do tại sao: Các lớp con sẽ gọi [super copyWithZone:zone] và mong đợi để lấy lại một thể hiện của lớp thích hợp, không phải là một thể hiện của lớp siêu.

  2. Tôi truy cập trực tiếp vào ivars, vì vậy tôi không cần phải lo lắng về bất kỳ phản ứng phụ nào mà tôi có thể thêm vào thiết lập thuộc tính (ví dụ: tạo thông báo) sau này. Hãy nhớ rằng, các lớp con được tự do ghi đè bất kỳ phương thức nào. Trong ví dụ của bạn, bạn đang gửi thêm hai tin nhắn cho mỗi ivar. Tôi sẽ thực hiện nó như sau:

Code:

- (id)copyWithZone:(NSZone *)zone { 
    Crime *newCrime = [super copyWithZone:zone]; 
    newCrime->_month = [_month copyWithZone:zone]; 
    newCrime->_category = [_category copyWithZone:zone]; 
    // etc... 
    return newCrime; 
} 

Tất nhiên, cho dù bạn sao chép ivars, giữ chân họ, hoặc chỉ gán chúng nên phản ánh những gì setters làm.

+32

nào trong hai cách tiếp cận để lựa chọn phụ thuộc vào việc thực hiện lớp cha 'NSCopying'. Ví dụ, 'NSObject' không, do đó, gọi' [super copyWithZone: zone] 'sẽ ném một ngoại lệ. – Costique

+0

Nó nói/Người dùng/ws403216/Máy tính để bàn/Demo/Demo/Tội phạm.m: 21: 28: Không hiển thị @interface cho 'NSObject' khai báo bộ chọn 'copyWithZone:' Siêu lớp Crime.m trong trường hợp của tôi là NSObject. –

+10

@NitinMalguri Như chú thích trước đó chỉ ra, bạn chỉ nên gọi '[super copyWithZone: zone]' nếu lớp cha hỗ trợ NSCopying, nếu không bạn nên gọi '[[[class] allocWithZone: zone] init]' và copy fields theo yêu cầu. – Tony

6

Hành vi sao chép mặc định của phương thức copyWithZone: với các đối tượng được cung cấp SDK là "bản sao nông". Điều đó có nghĩa là nếu bạn gọi copyWithZone: trên đối tượng NSString, nó sẽ tạo bản sao nông nhưng không sao chép sâu. Sự khác biệt giữa bản sao nông và sâu là:

Bản sao nông của đối tượng sẽ chỉ sao chép tham chiếu đến đối tượng của mảng ban đầu và đặt chúng vào mảng mới.

Một bản sao sâu sẽ thực sự sao chép các đối tượng riêng lẻ có trong đối tượng. Điều này được thực hiện bằng cách gửi từng đối tượng riêng lẻ một thông báo copyWithZone: trong phương thức lớp tùy chỉnh của bạn.

INSHORT: Để lấy bản sao nông bạn gọi retain hoặc strong trên tất cả các biến mẫu. Để có được bản sao sâu bạn gọi copyWithZone: trên tất cả các biến mẫu trong lớp tùy chỉnh của bạn copyWithZone: triển khai. Bây giờ là sự lựa chọn của bạn để lựa chọn.

0

Đây là mô hình của tôi.

#import <Foundation/Foundation.h> 
@interface RSRFDAModel : NSObject 


@property (nonatomic, assign) NSInteger objectId; 

@property (nonatomic, copy) NSString *name; 

@property (nonatomic, strong) NSArray<RSRFDAModel *> *beans; 


@end 


#import "RSRFDAModel.h" 

@interface RSRFDAModel() <NSCopying> 

@end 

@implementation RSRFDAModel 


-(id)copyWithZone:(NSZone *)zone { 
    RSRFDAModel *model = [[[self class] allocWithZone:zone] init]; 

    model.objectId = self.objectId; 
    model.name = self.name; 
    model.beans = [self.beans mutableCopy]; 

    return model; 
} 

@end 
0

Làm thế nào về việc này mà thực hiện sao chép sâu:

/// Class Foo has two properties: month and category 
- (id)copyWithZone:(NSZone *zone) { 
    Foo *newFoo; 
    if ([self.superclass instancesRespondToSelector:@selector(copyWithZone:)]) { 
     newFoo = [super copyWithZone:zone]; 
    } else { 
     newFoo = [[self.class allocWithZone:zone] init]; 
    } 
    newFoo->_month = [_month copyWithZone:zone]; 
    newFoo->_category = [_category copyWithZone:zone]; 
    return newFoo; 
} 
Các vấn đề liên quan