Frage Implementieren von NSCopying


Ich habe das gelesen NSCopying Aber ich bin immer noch sehr unsicher, wie ich das 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

Das Vendor Klasse hat ein Array von Objekten namens Car.

Meine 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

Damit, Vendor hält ein Array von Car Objekte. Car enthält 2 Arrays anderer benutzerdefinierter Objekte.

Beide Vendor und Car sind init von einem Wörterbuch. Ich werde eine dieser Methoden hinzufügen, die relevant sein können 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;
}

Also um das Gruselproblem zusammenzufassen.

Ich muss ein Array von kopieren Vendor Objekte. Ich glaube, ich muss das umsetzen NSCopying Protokoll auf Vendor, was bedeuten kann, dass ich es auch umsetzen muss Car schon seit Vendor hält ein Array von Cars. Das bedeutet, dass ich es auch für die Klassen implementieren muss, die in den 2 Arrays des Car Objekt.

Ich würde es sehr schätzen, wenn ich eine Anleitung zur Umsetzung bekommen könnte NSCopying Protokoll auf VendorIch kann nirgendwo Tutorials finden.


76
2017-11-03 16:28


Ursprung


Antworten:


Implementieren NSCkopieren, Ihr Objekt muss auf die antworten -copyWithZone: Wähler. So erklärst du, dass du dich daran anpasst:

@interface MyObject : NSObject <NSCopying> {

Dann in der Implementierung Ihres Objekts (Ihre .m Datei):

- (id)copyWithZone:(NSZone *)zone
{
    // Copying code here.
}

Was sollte dein Code tun? Erstellen Sie zunächst eine neue Instanz des Objekts, das Sie aufrufen können [[[self class] alloc] init] um ein initialisiertes Objekt der aktuellen Klasse zu erhalten, das gut für Unterklassen funktioniert. Dann für alle Instanzvariablen, die eine Unterklasse von sind NSObject das Kopieren unterstützt, können Sie anrufen [thatObject copyWithZone:zone] für das neue Objekt. Für primitive Typen (int, char, BOOL und Freunde) setzen Sie die Variablen einfach gleich. Also, für Ihren objektorientierten Verkäufer würde es so aussehen:

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

174
2017-11-03 16:42



Diese Antwort ist ähnlich wie die angenommen, aber verwendet allocWithZone: und wird für ARC aktualisiert. NSZone ist die Basisklasse für die Speicherzuweisung. Beim Ignorieren NSZone könnte für die meisten Fälle funktionieren, ist es immer noch falsch.

Um richtig zu implementieren NSCopying Sie müssen eine Protokollmethode implementieren, die eine neue Kopie des Objekts mit Eigenschaften zuweist, die den Werten des Originals entsprechen.

Geben Sie in der Schnittstellendeklaration in der Kopfzeile an, dass Ihre Klasse das implementiert NSCopying Protokoll:

@interface Car : NSObject<NSCopying>
{
 ...
}

In der .m-Implementierung fügen Sie a -(id)copyWithZone Methode, die in etwa wie folgt aussieht:

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

4
2018-01-03 17:19



Schnelle Version

Ruf einfach an object.copy() um die Kopie zu erstellen.

Ich habe es nicht benutzt copy() für Werttypen, da diese "automatisch" kopiert werden. Aber ich musste es gebrauchen copy() zum class Arten.

Ich habe das ignoriert NSZone Parameter weil Dokumente sag es ist veraltet:

Dieser Parameter wird ignoriert. Speicherzonen werden nicht mehr von verwendet   Ziel c.

Bitte beachten Sie auch, dass dies eine vereinfachte Implementierung ist. Wenn Sie Unterklassen haben Es wird ein bisschen Tricker und Sie sollten dynamischen Typ verwenden: 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
    }
}

0
2018-01-08 16:38