NSCopying लागू करना


84

मैंने पढ़ा है 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एक शब्दकोश से init कर रहे हैं। मैं इनमें से एक विधि जोड़ूंगा, वे प्रासंगिक हो सकती हैं या नहीं।

-(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, जिसका मतलब यह हो सकता है कि मुझे इसे लागू करने की आवश्यकता है Carक्योंकि एस Vendorकी एक सरणी रखती है Car। इसका मतलब है कि मुझे इसे उन वर्गों पर भी लागू करने की आवश्यकता है जो 2 सरणियों से संबंधित हैंCar ऑब्जेक्ट ।

अगर मैं NSCopyingप्रोटोकॉल को लागू करने के बारे में कुछ मार्गदर्शन प्राप्त कर सकता हूं, तो मैं वास्तव में इसकी सराहना करूंगा Vendor। मुझे इस पर कोई भी ट्यूटोरियल नहीं मिल सकता है।


क्या आपने NSCopying का प्रलेखन पढ़ा है? जरूरत पड़ने पर मैंने इसे काफी स्पष्ट पाया।
jv42

4
हां, इसे पढ़ें और इसे फिर से पढ़ें। मुझे शायद ही कभी ऐप्पल डॉक्स से सीखने में आसान लगता है, हालांकि वे प्रोग्रामिंग करते समय तरीकों आदि को खोजने के लिए महान हैं। धन्यवाद -कोड

जवाबों:


186

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और दोस्तों) बस चर बराबर होना निर्धारित किया है। तो, आपके ओब्जेक्ट वेंडर के लिए, यह इस तरह दिखेगा:

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

2
@ कोड: copyआमतौर पर एक उथली प्रति के रूप में कार्यान्वित किया जाता है जैसे जेफ ने दिखाया। यह असामान्य है - हालांकि यह समझ से बाहर नहीं है - कि आप पूरी तरह से गहरी प्रतिलिपि चाहते हैं (जहां हर तरह से नीचे नकल की जाती है)। गहरी प्रतियां बहुत अधिक परेशानी हैं, इसलिए, आप आमतौर पर यह सुनिश्चित करना चाहते हैं कि वास्तव में आप क्या चाहते हैं।
चक

3
आपके कोड में एक समस्या है जहां आप अपने उपवर्गों की नकल करते हैं, क्योंकि copyWithZone:1 के संदर्भ गिनती के साथ एक वस्तु लौटाता है और कोई भी ऑटोरेलिज़ ऐसा नहीं है जो एक रिसाव का कारण होगा। आपको कम से कम एक ऑटोरिलिज़ जोड़ने की आवश्यकता है।
मेरियस

22
इसके बजाय [[self class] alloc]उपयोग नहीं करना चाहिए allocWithZone? इसे ऊपर लाने के लिए क्षमा करें।

1
दोस्तों, मुझे लगता है कि एआरसी (किसी भी ऐप के लिए न्यूनतम समर्थित IOS 4.3 है) का उपयोग करके, आपको रिलीज़ और ऑटो-रिलीज़ के बारे में चिंता करने की आवश्यकता नहीं है।
ऋषभ

1
@GeneralMike: यह शायद एक अलग प्रश्न होना चाहिए, लेकिन सामान्य तौर पर (देखें कि मैंने वहां क्या किया?), आप एक गहरी प्रतिलिपि के दौरान मूल से प्रत्येक वस्तु की प्रतिलिपि बनाना सुनिश्चित करना चाहते हैं - और सुनिश्चित करें कि उनकी -copyविधियाँ भी गहरी प्रतियां हैं ।
जेफ केली

6

यह उत्तर स्वीकृत के समान है, लेकिन allocWithZone:एआरसी के लिए उपयोग और अद्यतन किया जाता है। मेमोरी को आवंटित करने के लिए 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;
}

2

स्विफ्ट संस्करण

बस कॉल करना object.copy() कॉपी बनाने के लिए ।

copy()जब से "स्वचालित रूप से" की नकल की जाती है, मैंने मूल्य प्रकारों के लिए उपयोग नहीं किया लेकिन मैं का इस्तेमाल किया था copy()के लिए classप्रकार के।

मैंने NSZoneपैरामीटर को अनदेखा कर दिया क्योंकि डॉक्स का कहना है कि यह पदावनत है:

इस पैरामीटर की अनदेखी की जाती है। मेमोरी जोन अब ऑब्जेक्टिव-सी द्वारा उपयोग नहीं किए जाते हैं।

इसके अलावा, कृपया ध्यान दें कि यह एक सरलीकृत कार्यान्वयन है। यदि आपके पास उपवर्ग हैं तो यह थोड़ा पेचीदा हो जाता है और आपको गतिशील प्रकार का उपयोग करना चाहिए 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
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.