Pertanyaan Menerapkan NSCopying


Saya sudah membaca NSCopying dokumen tetapi saya masih sangat tidak yakin tentang bagaimana menerapkan apa yang diperlukan.

Kelasku 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

Itu Vendor kelas memiliki larik objek yang disebut Car.

Saya Car obyek:

@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

Begitu, Vendor menyimpan array Car objek. Car menyimpan 2 larik objek kustom lainnya.

Kedua Vendor dan Car adalah init dari kamus. Saya akan menambahkan salah satu metode ini, mereka mungkin atau mungkin tidak relevan.

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

Jadi untuk meringkas masalah yang menakutkan.

Saya perlu menyalin array Vendor objek. Saya percaya saya perlu menerapkan NSCopying protokol aktif Vendor, yang mungkin berarti saya perlu menerapkannya juga Car sejak Vendor menyimpan array Cars. Itu berarti saya juga perlu menerapkannya pada kelas yang diadakan di 2 array milik Car obyek.

Saya akan sangat menghargai jika saya bisa mendapatkan beberapa petunjuk tentang penerapannya NSCopying protokol aktif VendorSaya tidak dapat menemukan tutorial tentang ini di mana saja.


76
2017-11-03 16:28


asal


Jawaban:


Untuk melaksanakan NSCopying, objek Anda harus merespons -copyWithZone: pemilih. Inilah cara Anda menyatakan bahwa Anda sesuai dengannya:

@interface MyObject : NSObject <NSCopying> {

Kemudian, dalam implementasi objek Anda (Anda .m mengajukan):

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

Apa yang harus dilakukan kode Anda? Pertama, buat instance baru objek — Anda dapat menelepon [[[self class] alloc] init] untuk mendapatkan obejct diinisialisasi dari kelas saat ini, yang bekerja dengan baik untuk subclassing. Kemudian, untuk setiap variabel instan yang merupakan subkelas NSObject yang mendukung penyalinan, Anda bisa menelepon [thatObject copyWithZone:zone] untuk objek baru. Untuk tipe primitif (int, char, BOOL dan teman-teman) hanya mengatur variabel agar sama. Jadi, untuk Vendor obejct Anda, ini akan terlihat seperti ini:

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



Jawaban ini mirip dengan yang diterima, tetapi digunakan allocWithZone: dan diperbarui untuk ARC. NSZone adalah kelas fondasi untuk mengalokasikan memori. Saat mengabaikan NSZone mungkin bekerja untuk sebagian besar kasus, itu masih salah.

Untuk benar menerapkan NSCopying Anda harus menerapkan metode protokol yang mengalokasikan salinan objek baru, dengan properti yang sesuai dengan nilai asli.

Dalam deklarasi antarmuka di header, tentukan bahwa kelas Anda mengimplementasikan NSCopying protokol:

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

Dalam implementasi .m tambahkan a -(id)copyWithZone metode yang terlihat seperti berikut:

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



Versi Swift

Telepon saja object.copy() untuk membuat salinan.

Saya tidak menggunakan copy() untuk jenis nilai karena itu disalin "secara otomatis." Tetapi saya harus menggunakannya copy() untuk class jenis.

Saya mengabaikan NSZone parameter karena dokumen katakan itu tidak lagi digunakan:

Parameter ini diabaikan. Zona memori tidak lagi digunakan oleh   Objective-C.

Juga, harap dicatat bahwa ini adalah implementasi yang disederhanakan. Jika Anda memiliki subclass itu sedikit menipu dan Anda harus menggunakan tipe dinamis: 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