iphone ios objective-c nscopying

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; }