Wdrażanie NSCopying

Przeczytałem NSCopying dokumenty, ale nadal nie jestem pewien, jak wdrożyć to, co jest wymagane.

Moja klasa 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

Klasa Vendor posiada tablicę obiektów o nazwie Car.

Mój Car obiekt:

@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

Tak więc Vendor przechowuje tablicę Car obiektów. Car przechowuje 2 tablice innych obiektów niestandardowych.

Zarówno Vendor jak i Car są init ze słownika. Dodam jedną z tych metod, mogą być istotne lub nie.

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

Tak aby podsumuj straszny problem.

Muszę skopiować tablicę Vendor obiektów. Uważam, że muszę zaimplementować protokół NSCopying na Vendor, co może oznaczać, że muszę zaimplementować go również na Car, ponieważ Vendor posiada tablicę Cars. oznacza to, że muszę również zaimplementować go na klasach, które są utrzymywane w dwóch tablicach należących do obiektu Car.

Byłbym naprawdę wdzięczny, gdybym mógł uzyskać wskazówki dotyczące implementacji NSCopying protokołu na Vendor, nie mogę znaleźć żadnych tutoriali na ten temat gdziekolwiek.

Author: Mitalkumar Gamit, 2010-11-03

3 answers

Aby zaimplementować NSCopying, obiekt musi odpowiedzieć na selektor -copyWithZone:. Oto jak deklarujesz, że się do niego dostosowujesz:

@interface MyObject : NSObject <NSCopying> {

Następnie w implementacji obiektu (Pliku .m):

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

Co powinien zrobić twój kod? Najpierw Utwórz nową instancję obiektu-możesz wywołać [[[self class] alloc] init], aby uzyskać zainicjalizowany objct bieżącej klasy, która działa dobrze przy podklasowaniu. Następnie, dla zmiennych instancji, które są podklasą NSObject, która obsługuje kopiowanie, można może wywołać [thatObject copyWithZone:zone] dla nowego obiektu. Dla prymitywnych typów (int, char, BOOL i przyjaciele) wystarczy ustawić zmienne na równe. Więc, dla Twojego sprzedawcy obejct, wyglądałoby to tak:

- (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;
}
 176
Author: Jeff Kelley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-27 19:35:17

Ta odpowiedź jest podobna do zaakceptowanej, ale używa allocWithZone: i jest aktualizowana dla ARC. NSZone to podstawowa klasa alokacji pamięci. Chociaż ignorowanie NSZone może działać w większości przypadków, nadal jest nieprawidłowe.

Aby poprawnie zaimplementować NSCopying należy zaimplementować metodę protokołu, która przydziela nową kopię obiektu, z właściwościami odpowiadającymi wartościom oryginału.

W deklaracji interfejsu w nagłówku określ, że twoja klasa implementuje NSCopying protokół:

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

W .implementacja m dodaje metodę -(id)copyWithZone, która wygląda mniej więcej tak:

- (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;
}
 5
Author: Justin Meiners,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-04 00:42:43

Wersja Swift

Po Prostu zadzwoń object.copy(), aby utworzyć kopię.

Nie używałem copy() dla typów wartości, ponieważ są one kopiowane " automatycznie."Ale musiałem użyć copy() dla class typów.

Zignorowałem parametr NSZone, ponieważ docs mówią, że jest przestarzały:

Ten parametr jest ignorowany. Strefy pamięci nie są już używane przez Objective-C.

Należy również pamiętać, że jest to uproszczona implementacja. Jeśli masz podklasy robi się trochę trudniej i powinieneś użyć dynamicznego typu: 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
Author: kgaidis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-08 16:52:07