实施NSCopying

79 iphone objective-c nscopying ios

我已经阅读了NSCopying文档,但我仍然不确定如何实现所需的内容.

我的班级Vendor:

@interface Vendor : NSObject 
{
    NSString        *vendorID;
    NSMutableArray  *availableCars;
    BOOL            atAirport;
}

@property (nonatomic, copy) NSString *vendorID;
@property (nonatomic, retain) NSMutableArray *availableCars;
@property (nonatomic, assign) BOOL atAirport;

- (id)initFromVehVendorAvailsDictionary:(NSDictionary *)vehVendorAvails;

@end
Run Code Online (Sandbox Code Playgroud)

Vendor类有称为对象的数组Car.

我的Car目标:

@interface Car : NSObject 
{
    BOOL            isAvailable;
    NSString        *transmissionType;
    NSMutableArray  *vehicleCharges; 
    NSMutableArray  *fees; 
}

@property (nonatomic, assign) BOOL isAvailable;
@property (nonatomic, copy) NSString *transmissionType;
@property (nonatomic, retain) NSMutableArray *vehicleCharges;
@property (nonatomic, retain) NSMutableArray *fees;

- (id) initFromVehicleDictionary:(NSDictionary *)vehicleDictionary;

@end
Run Code Online (Sandbox Code Playgroud)

所以,Vendor拥有一个Car对象数组.Car拥有2个其他自定义对象的数组.

双方VendorCar从字典初始化.我将添加其中一种方法,它们可能相关也可能不相关.

-(id)initFromVehVendorAvailsDictionary:(NSDictionary *)vehVendorAvails {

    self.vendorCode      = [[vehVendorAvails objectForKey:@"Vendor"] 
                           objectForKey:@"@Code"];

    self.vendorName      = [[vehVendorAvails objectForKey:@"Vendor"] 
                           objectForKey:@"@CompanyShortName"];

    self.vendorDivision  = [[vehVendorAvails objectForKey:@"Vendor"]   
                           objectForKey:@"@Division"];

    self.locationCode    = [[[vehVendorAvails objectForKey:@"Info"] 
                           objectForKey:@"LocationDetails"] 
                           objectForKey:@"@Code"];

    self.atAirport       = [[[[vehVendorAvails objectForKey:@"Info"] 
                           objectForKey:@"LocationDetails"] 
                           objectForKey:@"@AtAirport"] boolValue];

    self.venLocationName = [[[vehVendorAvails objectForKey:@"Info"] 
                           objectForKey:@"LocationDetails"] 
                           objectForKey:@"@Name"];

    self.venAddress      = [[[[vehVendorAvails objectForKey:@"Info"] 
                           objectForKey:@"LocationDetails"] 
                           objectForKey:@"Address"] 
                           objectForKey:@"AddressLine"];

    self.venCountryCode  = [[[[[vehVendorAvails objectForKey:@"Info"]  
                           objectForKey:@"LocationDetails"] 
                           objectForKey:@"Address"] 
                           objectForKey:@"CountryName"]
                           objectForKey:@"@Code"];

    self.venPhone        = [[[[vehVendorAvails objectForKey:@"Info"]  
                           objectForKey:@"LocationDetails"]        
                           objectForKey:@"Telephone"] 
                           objectForKey:@"@PhoneNumber"];

    availableCars        = [[NSMutableArray alloc] init];

    NSMutableArray *cars = (NSMutableArray *)[vehVendorAvails objectForKey:@"VehAvails"];

    for (int i = 0; i < [cars count]; i++) {

        Car *car = [[Car alloc] initFromVehicleDictionary:[cars objectAtIndex:i]];
        [availableCars addObject:car];
        [car release];
    }

    self.venLogo = [[[vehVendorAvails objectForKey:@"Info"] 
                   objectForKey:@"TPA_Extensions"] 
                   objectForKey:@"VendorPictureURL"];

    return self;
}
Run Code Online (Sandbox Code Playgroud)

所以总结一下这个可怕的问题.

我需要复制一个Vendor对象数组.我相信我需要实现NSCopying协议Vendor,这可能意味着我需要实现它,Car因为它Vendor拥有一个Cars 数组.这意味着我还需要在属于该Car对象的2个数组中保存的类上实现它.

如果我能获得有关实现NSCopying协议的指导,我真的很感激Vendor,我在任何地方都找不到任何关于此的教程.

Jef*_*ley 180

要实现NSCopying,您的对象必须响应-copyWithZone:选择器.以下是您声明符合它的方式:

@interface MyObject : NSObject <NSCopying> {
Run Code Online (Sandbox Code Playgroud)

然后,在对象的实现(您的.m文件)中:

- (id)copyWithZone:(NSZone *)zone
{
    // Copying code here.
}
Run Code Online (Sandbox Code Playgroud)

你的代码应该怎么做?首先,创建一个对象的新实例 - 您可以调用它[[[self class] alloc] init]来获取当前类的初始化对象,这对于子类化很有效.然后,对于任何NSObject支持复制的子类的实例变量,可以调用[thatObject copyWithZone:zone]新对象.对于原始类型(int,char,BOOL和朋友)刚刚成立的变量是相等的.因此,对于您的obejct供应商,它看起来像这样:

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[[self class] alloc] init];

    if (copy) {
        // Copy NSObject subclasses
        [copy setVendorID:[[self.vendorID copyWithZone:zone] autorelease]];
        [copy setAvailableCars:[[self.availableCars copyWithZone:zone] autorelease]];

        // Set primitives
        [copy setAtAirport:self.atAirport];
    }

    return copy;
}
Run Code Online (Sandbox Code Playgroud)

  • 不应该`[[self class] alloc]`使用`allocWithZone`而不是?很抱歉提起这件事. (22认同)
  • 复制子类的代码中存在一个问题,因为`copyWithZone:`返回引用计数为1且没有自动释放的对象,这将导致泄漏.您需要添加至少一个自动释放. (3认同)
  • @Code:`copy` 通常像 Jeff 展示的那样实现为浅拷贝。这是不寻常的——尽管并非不可思议——你想要一个完整的深拷贝(所有的东西都被复制)。深拷贝也更麻烦,因此您通常希望确保这确实是您想要的。 (2认同)

Jus*_*ers 6

这个答案类似于接受,但使用allocWithZone:和更新ARC.NSZone是分配内存的基础类.虽然忽略NSZone可能适用于大多数情况,但它仍然是不正确的.

要正确实现NSCopying,必须实现一个协议方法,该方法分配对象的新副本,其属性与原始值匹配.

在标头的接口声明中,指定您的类实现NSCopying协议:

@interface Car : NSObject<NSCopying>
{
 ...
}
Run Code Online (Sandbox Code Playgroud)

在.m实现中添加一个-(id)copyWithZone类似于以下内容的方法:

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

    if (carCopy)
    {
        carCopy.isAvailable = _isAvailable;
        carCopy.transmissionType = _transmissionType;
        ... // assign all other properties.
    }

    return carCopy;
}
Run Code Online (Sandbox Code Playgroud)