Câu hỏi Triển khai NSCopying


Tôi đã đọc NSCopying tài liệu nhưng tôi vẫn rất không chắc chắn về cách thực hiện những gì được yêu cầu.

Lớp học của tôi 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

Các Vendor lớp có một mảng các đối tượng được gọi là Car.

Của tôi Car vật:

@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

Vì thế, Vendor giữ một mảng Car các đối tượng. Car chứa 2 mảng của các đối tượng tùy chỉnh khác.

Cả hai Vendor và Car là init từ một từ điển. Tôi sẽ thêm một trong những phương pháp này, chúng có thể có hoặc không có liên quan.

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

Vì vậy, để tóm tắt các vấn đề đáng sợ.

Tôi cần phải sao chép một mảng Vendor các đối tượng. Tôi tin rằng tôi cần phải thực hiện NSCopying giao thức trên Vendor, có thể có nghĩa là tôi cũng cần phải triển khai nó Car kể từ đó Vendor giữ một mảng CarS. Điều đó có nghĩa là tôi cũng cần phải thực hiện nó trên các lớp được tổ chức trong 2 mảng thuộc về Car vật.

Tôi thực sự đánh giá cao nếu tôi có thể nhận được một số hướng dẫn về việc triển khai NSCopying giao thức trên Vendor, Tôi không thể tìm thấy bất kỳ hướng dẫn về điều này bất cứ nơi nào.


76
2017-11-03 16:28


gốc


Bạn đã đọc tài liệu về NSCopying chưa? Tôi thấy nó khá rõ ràng khi cần thiết. - jv42
Có, đọc và nó đọc lại nó. Tôi hiếm khi tìm thấy tài liệu táo dễ dàng để tìm hiểu từ, mặc dù họ là tuyệt vời cho việc tìm kiếm phương pháp vv trong khi lập trình. Thanks -Code


Các câu trả lời:


Thực hiện NSCopying, đối tượng của bạn phải trả lời -copyWithZone: bộ chọn. Dưới đây là cách bạn tuyên bố rằng bạn tuân thủ:

@interface MyObject : NSObject <NSCopying> {

Sau đó, trong việc triển khai đối tượng của bạn (của bạn .m tập tin):

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

Mã của bạn nên làm gì? Đầu tiên, tạo một đối tượng mới của đối tượng — bạn có thể gọi [[[self class] alloc] init] để có được một obejct khởi tạo của lớp hiện tại, mà hoạt động tốt cho subclassing. Sau đó, đối với bất kỳ biến mẫu nào là lớp con của NSObject hỗ trợ sao chép, bạn có thể gọi [thatObject copyWithZone:zone] cho đối tượng mới. Đối với các kiểu nguyên thủy (int, char, BOOL và bạn bè) chỉ cần đặt các biến bằng nhau. Vì vậy, đối với Nhà cung cấp đáng ngờ của bạn, nó trông giống như sau:

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



@ Mã: copy thường được thực hiện như một bản sao nông như Jeff đã cho thấy. Nó không bình thường - mặc dù không phải là không thể tưởng tượng - rằng bạn muốn có một bản sao sâu đầy đủ (nơi tất cả mọi thứ tất cả các con đường xuống được sao chép). Các bản sao sâu cũng có nhiều rắc rối hơn, vì vậy bạn thường muốn chắc chắn đó thực sự là những gì bạn muốn. - Chuck
Có một vấn đề trong mã của bạn, nơi bạn sao chép các lớp con của bạn, như copyWithZone: trả về một đối tượng có số tham chiếu là 1 và không có autorelease, điều này sẽ gây ra rò rỉ. Bạn cần phải thêm ít nhất một autorelease. - Marius
Không nên [[self class] alloc] sử dụng allocWithZone thay thế? Xin lỗi vì đã mang cái này lên. - jweyrich
Folks, tôi giả sử bằng cách sử dụng ARC (kể từ khi IOS hỗ trợ tối thiểu cho bất kỳ ứng dụng nào là 4.3), bạn không cần phải lo lắng về việc phát hành và tự động phát hành. - rishabh
@GeneralMike: Điều này có lẽ nên là một câu hỏi riêng biệt, nhưng nói chung (xem những gì tôi đã làm ở đó?), Bạn muốn đảm bảo sao chép mọi đối tượng từ bản gốc trong một bản sao sâu — và đảm bảo rằng -copy phương pháp cũng làm bản sao sâu. - Jeff Kelley


Câu trả lời này tương tự như được chấp nhận, nhưng sử dụng allocWithZone: và được cập nhật cho ARC. NSZone là lớp nền tảng để cấp phát bộ nhớ. Trong khi bỏ qua NSZone có thể làm việc cho hầu hết các trường hợp, nó vẫn không chính xác.

Để triển khai chính xác NSCopying bạn phải thực hiện một phương thức giao thức phân bổ một bản sao mới của đối tượng, với các thuộc tính phù hợp với các giá trị của bản gốc.

Trong khai báo giao diện trong tiêu đề, chỉ định rằng lớp của bạn triển khai thực hiện NSCopying giao thức:

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

Trong việc thực hiện .m thêm một -(id)copyWithZone phương thức trông giống như sau:

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





Phiên bản Swift

Chỉ cần gọi object.copy() để tạo bản sao.

Tôi đã không sử dụng copy() đối với các loại giá trị vì chúng được sao chép "tự động". Nhưng tôi phải sử dụng copy() cho class loại.

Tôi bỏ qua NSZone tham số vì tài liệu nói rằng nó không được dùng nữa:

Tham số này bị bỏ qua. Khu vực bộ nhớ không còn được sử dụng bởi   Mục tiêu-C.

Ngoài ra, xin lưu ý rằng đây là một triển khai đơn giản. Nếu bạn có lớp con nó được một chút tricker và bạn nên sử dụng loại năng động: 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