ऑब्जेक्टिव-सी में किसी ऑब्जेक्ट को कॉपी कैसे करें


112

मुझे एक कस्टम ऑब्जेक्ट को डीप कॉपी करने की आवश्यकता है जिसमें स्वयं की वस्तुएं हैं। मैं चारों ओर पढ़ रहा हूं और थोड़ा उलझन में हूं कि कैसे NSCopying विरासत में मिला और कैसे NSCopyObject का उपयोग किया जाए।


1
महान ट्यूटोरियल समझ प्रतिलिपि, mutableCopy और copyWithZone के लिए
horkavlna

जवाबों:


192

हमेशा संदर्भ प्रकारों के साथ, "कॉपी" की दो धारणाएं होती हैं। मुझे यकीन है कि आप उन्हें जानते हैं, लेकिन पूर्णता के लिए।

  1. एक बिटवाइज़ कॉपी। इसमें, हम बस बिट के लिए मेमोरी बिट की नकल करते हैं - यह वही है जो NSCopyObject करता है। लगभग हमेशा, यह वह नहीं है जो आप चाहते हैं। ऑब्जेक्ट्स में आंतरिक स्थिति, अन्य ऑब्जेक्ट्स आदि होते हैं, और अक्सर यह धारणा बनाते हैं कि वे केवल उस डेटा के संदर्भों को पकड़े हुए हैं। बिटकॉइन प्रतियां इस धारणा को तोड़ती हैं।
  2. एक गहरी, तार्किक प्रति। इसमें, हम ऑब्जेक्ट की एक प्रति बनाते हैं, लेकिन वास्तव में इसे बिट द्वारा थोड़ा सा किए बिना - हम एक ऐसी वस्तु चाहते हैं जो सभी इरादों और उद्देश्यों के लिए समान हो, लेकिन मूल रूप से स्मृति-समरूप क्लोन नहीं है - ऑब्जेक्टिव सी मैनुअल ऐसी वस्तु को मूल रूप से "कार्यात्मक रूप से स्वतंत्र" कहता है। क्योंकि इन "बुद्धिमान" प्रतियों को बनाने का तंत्र कक्षा से कक्षा में भिन्न होता है, हम वस्तुओं को स्वयं उन्हें प्रदर्शन करने के लिए कहते हैं। यह NSCopying प्रोटोकॉल है।

आप बाद चाहते हैं। यदि यह आपकी खुद की वस्तुओं में से एक है, तो आपको बस NSCopying और कार्यान्वयन के लिए प्रोटोकॉल को अपनाने की आवश्यकता है - (id) copyWithZone: (NSZone *) ज़ोन। आप जो चाहें करने के लिए स्वतंत्र हैं; यद्यपि विचार यह है कि आप स्वयं की एक वास्तविक प्रति बनाते हैं और उसे वापस करते हैं। आप अपने सभी फ़ील्ड पर copyWithZone कहते हैं, एक गहरी प्रतिलिपि बनाने के लिए। एक सरल उदाहरण है

@interface YourClass : NSObject <NSCopying> 
{
   SomeOtherObject *obj;
}

// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
  // We'll ignore the zone for now
  YourClass *another = [[YourClass alloc] init];
  another.obj = [obj copyWithZone: zone];

  return another;
}

लेकिन आप इसे मुक्त करने के लिए ज़िम्मेदार कॉपी किए गए ऑब्जेक्ट के प्राप्तकर्ता को बना रहे हैं! क्या आपको autoreleaseयह नहीं करना चाहिए , या मैं यहां कुछ याद कर रहा हूं?
बोब्बोबोबो

30
@ बोबोबोबो: नहीं, ऑब्जेक्टिव-सी मेमोरी मैनेजमेंट का मूल नियम है: यदि आप किसी ऐसी विधि का उपयोग करते हैं, जिसका नाम "आवंटित" या "नया" से शुरू होता है या "कॉपी" होता है, तो आप किसी वस्तु का स्वामित्व लेते हैं। copyWithZone:इस मापदंड को पूरा करता है, इसलिए इसे +1 की एक बरकरार गणना के साथ एक वस्तु वापस करना होगा।
स्टीव मैडसेन

1
@ अदम क्या ज़ोन पास होने के allocबजाय उपयोग करने का कोई कारण allocWithZone:है?
रिचर्ड

3
खैर, ज़ोन आधुनिक ओएस एक्स आधारित रनटाइम में प्रभावी रूप से अप्रयुक्त हैं (यानी मुझे लगता है कि वे सचमुच कभी उपयोग नहीं किए जाते हैं)। लेकिन हां, आप कॉल कर सकते हैं allocWithZone
एडम राइट


25

Apple प्रलेखन कहते हैं

CopyWithZone का एक उपवर्ग संस्करण: विधि को इसके कार्यान्वयन को शामिल करने के लिए, पहले सुपर को संदेश भेजना चाहिए, जब तक कि उपवर्ग सीधे NSObject से नहीं उतरता।

मौजूदा उत्तर में जोड़ने के लिए

@interface YourClass : NSObject <NSCopying> 
{
   SomeOtherObject *obj;
}

// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
  YourClass *another = [super copyWithZone:zone];
  another.obj = [obj copyWithZone: zone];

  return another;
}

2
चूंकि YourClass NSObject से सीधे उतरता है, मुझे नहीं लगता कि यह यहाँ आवश्यक है
माइक

2
अच्छी बात है, लेकिन एक सामान्य नियम, इसकी लंबी श्रेणी के पदानुक्रम के मामले में।
साकिब सऊद

8
मैं एक त्रुटि मिली: No visible @interface for 'NSObject' declares the selector 'copyWithZone:'। मुझे लगता है कि यह केवल तब आवश्यक है जब हम कुछ अन्य कस्टम वर्ग से विरासत में प्राप्त कर रहे हैंcopyWithZone
सैम

1
other.obj = [[obj copyWithZone: zone] autorelease]; NSObject के सभी उपवर्गों के लिए। और आदिम datatypes के लिए आप बस उन्हें असाइन करते हैं -> एक और।
हरिसज़मैन

@ सम "NSObject खुद NSCopying प्रोटोकॉल का समर्थन नहीं करता है। उपवर्गों को प्रोटोकॉल का समर्थन करना चाहिए और copyWithZone: पद्धति को लागू करना चाहिए। copyWithZone का एक उपवर्ग संस्करण: विधि को सबसे पहले संदेश भेजना चाहिए, इसके कार्यान्वयन को शामिल करने के लिए, जब तक कि उपवर्ग सीधे नहीं उतरता। NSObject से। ” डेवलपर
.apple.com

21

मुझे उस कोड और मेरे बीच का अंतर नहीं पता है, लेकिन मुझे उस समाधान के साथ समस्या है, इसलिए मैंने थोड़ा और पढ़ा और पाया कि हमें इसे वापस करने से पहले ऑब्जेक्ट सेट करना होगा। मेरा मतलब कुछ इस तरह है:

#import <Foundation/Foundation.h>

@interface YourObject : NSObject <NSCopying>

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *line;
@property (strong, nonatomic) NSMutableString *tags;
@property (strong, nonatomic) NSString *htmlSource;
@property (strong, nonatomic) NSMutableString *obj;

-(id) copyWithZone: (NSZone *) zone;

@end


@implementation YourObject


-(id) copyWithZone: (NSZone *) zone
{
    YourObject *copy = [[YourObject allocWithZone: zone] init];

    [copy setNombre: self.name];
    [copy setLinea: self.line];
    [copy setTags: self.tags];
    [copy setHtmlSource: self.htmlSource];

    return copy;
}

मैंने इस जवाब को जोड़ा क्योंकि मुझे इस मुद्दे के साथ बहुत सारी समस्याएं हैं और मुझे कोई सुराग नहीं है कि ऐसा क्यों हो रहा है। मुझे अंतर नहीं पता है, लेकिन यह मेरे लिए काम कर रहा है और शायद यह दूसरों के लिए भी उपयोगी हो सकता है:)


3
another.obj = [obj copyWithZone: zone];

मुझे लगता है, कि यह लाइन मेमोरी लीक का कारण बनती है, क्योंकि आप objसंपत्ति के माध्यम से पहुंचते हैं (जो मुझे लगता है) घोषित किया गया है retain। इसलिए, संपत्ति के हिसाब से रिटेन काउंट बढ़ाया जाएगा copyWithZone

मेरा मानना ​​है कि यह होना चाहिए:

another.obj = [[obj copyWithZone: zone] autorelease];

या:

SomeOtherObject *temp = [obj copyWithZone: zone];
another.obj = temp;
[temp release]; 

नहींं, विधियाँ आवंटित, प्रतिलिपि, उत्परिवर्तनीय, नए को गैर-ऑटोरेल्ड ऑब्जेक्ट वापस करना चाहिए।
कोवपस

@ स्कोपस, क्या आपको यकीन है, कि आप मुझे सही समझ रहे हैं? मैं लौटी हुई वस्तु के बारे में बात नहीं कर रहा हूँ, मैं इसके बारे में बात कर रहा हूँ कि यह डेटा फ़ील्ड है।
सजुवर_जृग

हाँ, मेरा बुरा, क्षमा करें। क्या आप अपना जवाब किसी तरह संपादित कर सकते हैं ताकि मैं माइनस को हटा सकूं? :))
कोवपस

0

नकल के लिए -> ऑपरेटर का उपयोग भी होता है। उदाहरण के लिए:

-(id)copyWithZone:(NSZone*)zone
{
    MYClass* copy = [MYClass new];
    copy->_property1 = self->_property1;
    ...
    copy->_propertyN = self->_propertyN;
    return copy;
}

यहाँ तर्क परिणामी नकल वस्तु है जो मूल वस्तु की स्थिति को दर्शाती है। ""। ऑपरेटर साइड इफेक्ट्स को पेश कर सकता है क्योंकि यह एक कॉल गेटर्स होता है जो बदले में तर्क हो सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.