J'ai lu les documents NSCopying
mais je ne sais toujours pas comment implémenter ce qui est requis.
Ma classe 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 classe Vendor
possède un tableau d'objets appelé Car
.
Mon objet 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
Ainsi, Vendor
contient un tableau d'objets Car
. Car
contient 2 tableaux d'autres objets personnalisés.
Vendor
et Car
proviennent tous les deux d'un dictionnaire. J'ajouterai l'une de ces méthodes, elles peuvent ou non être pertinentes.
-(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;
}
Donc, pour résumer le problème effrayant.
J'ai besoin de copier un tableau d'objets Vendor
. Je crois que je dois implémenter le protocole NSCopying
sur Vendor
, ce qui peut signifier que je dois l'implémenter également sur Car
puisque Vendor
contient un tableau de Car
s. Cela signifie que je dois également l'implémenter sur les classes contenues dans les 2 tableaux appartenant à l'objet Car
.
J'apprécierais vraiment si je pouvais obtenir des conseils sur la mise en œuvre du protocole NSCopying
sur Vendor
, je ne trouve aucun tutoriel à ce sujet nulle part.
Pour implémenter NSCopying , votre objet doit répondre au -copyWithZone:
sélecteur. Voici comment vous déclarez vous y conformer:
@interface MyObject : NSObject <NSCopying> {
Ensuite, dans l'implémentation de votre objet (votre .m
fichier):
- (id)copyWithZone:(NSZone *)zone
{
// Copying code here.
}
Que doit faire votre code? Créez d'abord une nouvelle instance de l'objet - vous pouvez appeler [[[self class] alloc] init]
pour obtenir un objet initialisé de la classe actuelle, qui fonctionne bien pour le sous-classement. Ensuite, pour toutes les variables d'instance qui sont une sous-classe de NSObject
qui prend en charge la copie, vous pouvez appeler [thatObject copyWithZone:zone]
pour le nouvel objet. Pour les types primitifs (int
, char
, BOOL
et amis), définissez simplement les variables comme égales. Donc, pour votre fournisseur obejct, cela ressemblerait à ceci:
- (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;
}
Cette réponse est similaire à celle acceptée, mais utilise allocWithZone:
Et est mise à jour pour ARC. NSZone est une classe de base pour l'allocation de mémoire. Même si ignorer NSZone
peut fonctionner dans la plupart des cas, il est toujours incorrect.
Pour implémenter correctement NSCopying
, vous devez implémenter une méthode de protocole qui alloue une nouvelle copie de l'objet, avec des propriétés qui correspondent aux valeurs de l'original.
Dans la déclaration d'interface dans l'en-tête, spécifiez que votre classe implémente le protocole NSCopying
:
@interface Car : NSObject<NSCopying>
{
...
}
Dans l'implémentation .m, ajoutez une méthode -(id)copyWithZone
qui ressemble à ceci:
- (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;
}
Appelez simplement object.copy()
pour créer la copie.
Je n'ai pas utilisé copy()
pour les types de valeur car ceux-ci sont copiés "automatiquement". Mais j'ai dû utiliser copy()
pour class
types.
J'ai ignoré le paramètre NSZone
car docs dit qu'il est obsolète:
Ce paramètre est ignoré. Les zones de mémoire ne sont plus utilisées par Objective-C.
Veuillez également noter qu'il s'agit d'une implémentation simplifiée. Si vous avez des sous-classes cela devient un peu plus délicat et vous devez utiliser le type dynamique: 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
}
}