Ich habe die NSCopying
Dokumente gelesen , bin mir aber immer noch nicht sicher, wie ich die erforderlichen Maßnahmen umsetzen soll.
Meine Klasse 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
Die Vendor
Klasse verfügt über ein Array von Objekten, die aufgerufen werden Car
.
Mein Car
Objekt:
@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
So Vendor
hält eine Reihe von Car
Objekten. Car
Enthält 2 Arrays anderer benutzerdefinierter Objekte.
Beide Vendor
und Car
sind init aus einem Wörterbuch. Ich werde eine dieser Methoden hinzufügen, sie können relevant sein oder auch nicht.
-(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;
}
Um das gruselige Problem zusammenzufassen.
Ich muss eine Reihe von Vendor
Objekten kopieren . Ich glaube, ich muss das NSCopying
Protokoll implementieren Vendor
, was bedeuten kann, dass ich es auch implementieren muss, Car
da es Vendor
ein Array von Car
s enthält. Das heißt, ich muss es auch in den Klassen implementieren, die in den 2 zum Car
Objekt gehörenden Arrays enthalten sind .
Ich würde es wirklich begrüßen, wenn ich eine Anleitung zur Implementierung des NSCopying
Protokolls erhalten könnte Vendor
. Ich kann dazu nirgendwo Tutorials finden.
quelle
Antworten:
Um NSCopying zu implementieren , muss Ihr Objekt auf den
-copyWithZone:
Selektor reagieren . So erklären Sie, dass Sie sich daran anpassen:Dann in der Implementierung Ihres Objekts (Ihrer
.m
Datei):Was soll Ihr Code tun? Erstellen Sie zunächst eine neue Instanz des Objekts. Sie können aufrufen
[[[self class] alloc] init]
, um ein initialisiertes Objekt der aktuellen Klasse abzurufen, das sich gut für Unterklassen eignet. Anschließend können Sie für alle Instanzvariablen, die eine Unterklasse sindNSObject
, die das Kopieren unterstützt,[thatObject copyWithZone:zone]
das neue Objekt aufrufen . Für primitive Typen (int
,char
,BOOL
und Freunde) nur die Variablen gleich sein. Für Ihren obejct Vendor würde es also so aussehen:quelle
copy
wird normalerweise als flache Kopie implementiert, wie Jeff gezeigt hat. Es ist ungewöhnlich - wenn auch nicht unvorstellbar -, dass Sie eine vollständige, tiefe Kopie wünschen (bei der alles bis zum Ende kopiert wird). Tiefe Kopien sind auch viel schwieriger, daher möchten Sie im Allgemeinen sicher sein, dass dies wirklich das ist, was Sie wollen.copyWithZone:
ein Objekt mit dem Referenzzähler 1 zurückgegeben wird und keine automatische Freigabe erfolgt. Dies führt zu einem Leck. Sie müssen mindestens eine Autorelease hinzufügen.[[self class] alloc]
verwendenallocWithZone
stattdessen? Tut mir leid, dass ich das angesprochen habe.-copy
Methoden auch tiefe Kopien erstellen .Diese Antwort ähnelt der akzeptierten, verwendet
allocWithZone:
jedoch ARC und wird für ARC aktualisiert. NSZone ist eine Grundklasse für die Zuweisung von Speicher. Während das IgnorierenNSZone
in den meisten Fällen funktioniert, ist es immer noch falsch.Um korrekt zu implementieren
NSCopying
, müssen Sie eine Protokollmethode implementieren, die eine neue Kopie des Objekts mit Eigenschaften zuweist, die den Werten des Originals entsprechen.Geben Sie in der Schnittstellendeklaration im Header an, dass Ihre Klasse das
NSCopying
Protokoll implementiert :Fügen Sie in der .m-Implementierung eine
-(id)copyWithZone
Methode hinzu, die ungefähr so aussieht:quelle
Schnelle Version
Rufen Sie einfach
object.copy()
an, um die Kopie zu erstellen.Ich habe es nicht
copy()
für Werttypen verwendet, da diese "automatisch" kopiert werden. Aber ich musstecopy()
fürclass
Typen verwenden.Ich habe den
NSZone
Parameter ignoriert , weil Dokumente sagen, dass er veraltet ist:Bitte beachten Sie auch, dass dies eine vereinfachte Implementierung ist. Wenn Sie Unterklassen haben, wird es etwas kniffliger und Sie sollten den dynamischen Typ verwenden :
type(of: self).init(transmissionType: transmissionType)
.quelle