iphone - Implementando NSCopying
ios objective-c (3)
Versión Swift
Simplemente llame a object.copy()
para crear la copia.
No utilicé copy()
para los tipos de valor ya que esos se copian "automáticamente". Pero tuve que usar copy()
para class
tipos de class
.
NSZone
parámetro NSZone
porque los docs dicen que está en desuso:
Este parámetro es ignorado Zonas de memoria ya no son utilizadas por Objective-C.
Además, tenga en cuenta que esta es una implementación simplificada. Si tiene subclases , se torna un poco más complicado y debe usar el tipo dinámico: type(of: self).init(transmissionType: transmissionType)
.
class Vendor {
let vendorId: String
var availableCars: [Car] = []
init(vendorId: String) {
self.vendorId = vendorId
}
}
extension Vendor: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
let copy = Vendor(vendorId: vendorId)
if let availableCarsCopy = availableCars.map({$0.copy()}) as? [Car] {
copy.availableCars = availableCarsCopy
}
return copy
}
}
class Car {
let transmissionType: String
var isAvailable: Bool = false
var fees: [Double] = []
init(transmissionType: String) {
self.transmissionType = transmissionType
}
}
extension Car: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
let copy = Car(transmissionType: transmissionType)
copy.isAvailable = isAvailable
copy.fees = fees
return copy
}
}
He leído los documentos de NSCopying
pero aún no estoy seguro de cómo implementar lo que se requiere.
Mi clase 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
La clase Vendor
tiene una matriz de objetos llamada Car
.
Objeto My 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
Entonces, el Vendor
tiene una gran variedad de objetos de Car
. Car
tiene 2 matrices de otros objetos personalizados.
Tanto el Vendor
como el Car
son init de un diccionario. Agregaré uno de estos métodos, pueden ser relevantes o no.
-(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;
}
Entonces, para resumir el problema aterrador.
Necesito copiar una matriz de objetos del Vendor
. Creo que tengo que implementar el protocolo NSCopying
en el Vendor
, lo que puede significar que necesito implementarlo también en el Car
ya que el Vendor
tiene una serie de Car
. Eso significa que también necesito implementarlo en las clases que se llevan a cabo en las dos matrices que pertenecen al objeto Car
.
Realmente agradecería si pudiera obtener orientación sobre la implementación del protocolo NSCopying
en el Vendor
, no puedo encontrar ningún tutorial sobre este tema en ninguna parte.
Esta respuesta es similar a la aceptada, pero usa allocWithZone:
y se actualiza para ARC. NSZone es una clase básica para asignar memoria. Aunque ignorar NSZone
podría funcionar en la mayoría de los casos, sigue siendo incorrecto.
Para implementar correctamente NSCopying
, debe implementar un método de protocolo que asigne una nueva copia del objeto, con propiedades que coincidan con los valores del original.
En la declaración de interfaz en el encabezado, especifique que su clase implementa el protocolo NSCopying
:
@interface Car : NSObject<NSCopying>
{
...
}
En la implementación .m, agregue un método -(id)copyWithZone
que se parece a lo siguiente:
- (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;
}
Para implementar NSCopying , su objeto debe responder al selector -copyWithZone:
. Así es como declaras que estás de acuerdo:
@interface MyObject : NSObject <NSCopying> {
Luego, en la implementación de su objeto (su archivo .m
):
- (id)copyWithZone:(NSZone *)zone
{
// Copying code here.
}
¿Qué debería hacer tu código? Primero, cree una nueva instancia del objeto: puede llamar a [[[self class] alloc] init]
para obtener un objeto inicializado de la clase actual, que funciona bien para la creación de subclases. Luego, para cualquier variable de instancia que sea una subclase de NSObject
que admita la copia, puede llamar a [thatObject copyWithZone:zone]
para el nuevo objeto. Para tipos primitivos ( int
, char
, BOOL
y amigos) simplemente configure las variables para que sean iguales. Por lo tanto, para su vendedor de obejct, se vería así:
- (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;
}