[iphone] NSCopying 구현

NSCopying문서를 읽었 지만 필요한 것을 구현하는 방법에 대해 여전히 잘 모르겠습니다.

내 수업 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

Vendor클래스라는 객체의 배열이있다 Car.

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

그래서, 객체 Vendor의 배열을 보유 Car합니다. Car다른 사용자 지정 개체의 배열 2 개를 보유합니다.

Vendor및 둘 다 Car사전에서 초기화됩니다. 이 방법 중 하나를 추가하겠습니다. 관련성이있을 수도 있고 아닐 수도 있습니다.

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

그래서 무서운 문제를 요약합니다.

Vendor객체 배열을 복사해야 합니다. 에서 NSCopying프로토콜 을 구현해야한다고 생각 Vendor하는데, s 배열을 보유하고 Car있기 때문에 구현해야 할 수도 있습니다 . 즉, 객체에 속하는 2 개의 배열에있는 클래스에서도이를 구현해야 합니다.VendorCarCar

에서 NSCopying프로토콜을 구현하는 방법에 대한 지침을 얻을 수 있다면 정말 감사하겠습니다. 여기에 Vendor대한 튜토리얼은 어디에서도 찾을 수 없습니다.



답변

NSCopying 을 구현하려면 객체가 -copyWithZone:선택자에 응답해야합니다 . 준수를 선언하는 방법은 다음과 같습니다.

@interface MyObject : NSObject <NSCopying> {

그런 다음 개체의 구현 ( .m파일)에서 :

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

코드는 무엇을해야합니까? 먼저 개체의 새 인스턴스를 만듭니다. 호출 [[[self class] alloc] init]하여 현재 클래스의 초기화 된 개체 를 가져올 수 있습니다 . 이는 하위 클래스에 적합합니다. 그런 다음 NSObject복사를 지원 하는의 하위 클래스 인 인스턴스 변수 [thatObject copyWithZone:zone]에 대해 새 개체를 호출 할 수 있습니다 . 프리미티브 유형 ( int, char, BOOL친구)는 단지 동일하게 변수를 설정. 따라서 obejct Vendor의 경우 다음과 같이 표시됩니다.

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


답변

이 답변은 수락 된 것과 유사하지만 allocWithZone:ARC를 사용 하고 업데이트됩니다. NSZone은 메모리 할당을위한 기초 클래스입니다. 무시 NSZone는 대부분의 경우 작동 할 수 있지만 여전히 올바르지 않습니다.

올바르게 구현하려면 NSCopying원본 값과 일치하는 속성을 사용하여 개체의 새 복사본을 할당하는 프로토콜 메서드를 구현해야합니다.

헤더의 인터페이스 선언에서 클래스가 NSCopying프로토콜을 구현하도록 지정 합니다.

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

.m 구현 -(id)copyWithZone에서 다음과 같은 메서드를 추가합니다 .

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


답변

스위프트 버전

object.copy()사본을 만들려면 전화 하십시오.

copy()값 유형은 “자동으로”복사되므로 사용하지 않았습니다 . 그러나 나는 유형 에 사용해야 copy()했습니다 class.

문서에서 더 이상 사용되지 않는다고 말했기NSZone 때문에 매개 변수를 무시 했습니다.

이 매개 변수는 무시됩니다. Objective-C는 메모리 영역을 더 이상 사용하지 않습니다.

또한 이것은 단순화 된 구현입니다. 하위 클래스 가있는 경우 약간 까다로워지고 dynamic type :을 사용해야합니다 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
    }
}


답변