Внедрение NSCopying
Я прочитал документы 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
Класс 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
Итак, Vendor
содержит массив объектов Car
. Car
содержит 2 массива других пользовательских объектов.
Оба Vendor
и Car
являются init из словаря. Я добавлю один из этих методов, они могут быть или не быть релевантными.
-(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;
}
Итак, суммируем страшную проблему.
Мне нужно скопировать массив объектов Vendor
. Я считаю, что мне нужно реализовать протокол NSCopying
на Vendor
, что может означать, что мне нужно реализовать его также на Car
, поскольку Vendor
содержит массив Car
s. Это означает, что мне также нужно реализовать его на классах, которые хранятся в 2 массивах, принадлежащих объекту Car
.
Я бы очень признателен, если бы мог получить некоторые рекомендации по реализации протокола NSCopying
на Vendor
, я не могу найти никаких учебных пособий в этом месте.
Ответы
Ответ 1
Чтобы реализовать NSCopying, ваш объект должен ответить на селектор -copyWithZone:
. Вот как вы заявляете, что согласны с ним:
@interface MyObject : NSObject <NSCopying> {
Затем в реализации ваших объектов (ваш .m
файл):
- (id)copyWithZone:(NSZone *)zone
{
// Copying code here.
}
Что должен делать ваш код? Во-первых, создайте новый экземпляр объекта - вы можете вызвать [[[self class] alloc] init]
, чтобы получить инициализированный obejct текущего класса, который хорошо подходит для подкласса. Затем для любых переменных экземпляра, которые являются подклассом NSObject
, который поддерживает копирование, вы можете вызвать [thatObject copyWithZone:zone]
для нового объекта. Для примитивных типов (int
, char
, BOOL
и друзей) просто установите переменные равными. Итак, для вашего obejct Vendor, itd выглядит так:
- (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;
}
Ответ 2
Этот ответ аналогичен принятому, но использует allocWithZone:
и обновляется для ARC. NSZone - это класс фундамента для выделения памяти. Хотя игнорирование NSZone
может работать в большинстве случаев, оно по-прежнему неверно.
Чтобы правильно реализовать NSCopying
, вы должны реализовать метод протокола, который выделяет новую копию объекта со свойствами, соответствующими значениям оригинала.
В объявлении интерфейса в заголовке укажите, что ваш класс реализует протокол NSCopying
:
@interface Car : NSObject<NSCopying>
{
...
}
В реализации .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;
}