2012-05-31 15 views
6

मैं एक प्रतिनिधि वस्तु NumericTextFieldDelegate तो नामित अपने ही वर्ग में UITextFieldDelegate को लागू बनाया है मैं इस तरह से मेरी नियंत्रक में प्रतिनिधि प्रारंभ की है उत्पन्न करता है संकलक से यह चेतावनी:सीधे प्रारंभ प्रतिनिधि एआरसी चेतावनी और EXC_BAD_ACCESS दुर्घटना

Assigning retained object to unsafe property; object will be released after assignment 

इसका मतलब है कि जब मैं आवेदन चलाने के लिए और मैं UITextField ध्यान केंद्रित है कि वस्तु असाइनमेंट के बाद और वास्तव में जारी किया जाएगा मैं एक EXC_BAD_ACCESS एक मिल nd ऐप्लिकेशन क्रैश ...

एक ही तरीका है कि मैंने पाया एक कारखाने विधि है कि NumericTextFieldDelegate के कहने प्रेषण के साथ एक स्थिर चर पैदा कर रही है यह काम कर रहे हैं:

@interface NumericTextFieldDelegate : NSObject <UITextFieldDelegate> 

+(NumericTextFieldDelegate *) getDelegate; 

@end 

@implementation NumericTextFieldDelegate 

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 

    NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string]; 

    // This allows backspace 
    if ([resultingString length] == 0) { 
     return true; 
    } 

    NSInteger holder; 
    NSScanner *scan = [NSScanner scannerWithString: resultingString]; 

    return [scan scanInteger: &holder] && [scan isAtEnd]; 
} 

+(NumericTextFieldDelegate *) getDelegate { 
    static NumericTextFieldDelegate *del; 
    @synchronized(del) { 
     if(del == nil) 
      del = [NumericTextFieldDelegate new]; 
    } 
    return del; 
} 

@end 

और फिर जब मैं आवंटित इस तरह से प्रतिनिधि:

textFieldName.delegate = [NumericTextFieldDelegate getDelegate]; 

सब कुछ अच्छी तरह से काम करता है, लेकिन मेरे सवाल यह है:

क्यों मैं बस नहीं कर सकते कक्षा का एक अज्ञात नया उदाहरण असाइन करें? असाइनमेंट के बाद ऑब्जेक्ट स्वचालित रूप से क्यों जारी किया जाता है?

मुझे इस कामकाज की आवश्यकता क्यों है?

धन्यवाद।

+0

यह एक यूआईटीएक्स्टफाल्ड है, कस्टम नहीं। – aleroot

+1

विधि 'प्राप्त' के साथ उपसर्ग नहीं किए जाने चाहिए जब तक कि वे एक बहुत ही विशिष्ट प्रकार (जो यह नहीं है) हैं। – bbum

+0

@bbum मुझे जावा से प्राप्त उपसर्ग मिला है :-) टिप – aleroot

उत्तर

2

मैं @ इंजेगर विश्लेषण से सहमत हूं। UITextField इंस्टेंस का प्रतिनिधि एक प्रकार का कमजोर संदर्भ है। इसमें सौंपा गया प्रतिनिधि नहीं है। एआरसी के मुताबिक, प्रतिनिधि नील होगा, इसका कोई संदर्भ नहीं है। इसलिए, इसे रखने के लिए असाइनर तक होगा ताकि प्रतिनिधि को बुलाया जा सके।

- (void) somemethod { 
... 
id<UITextFieldDelegate> tempDelegate = [NumericTextFieldDelegate new]; 
textFieldName.delegate = tempDelegate; 
... 
} 

textFieldName के कहने somethod में स्थानीय रूप से बनाए गए एक प्रतिनिधि के लिए एक संदर्भ मिला है: आप कोड से पहले वैकल्पिक हल कुछ इस तरह है। विधि कॉल के बाद एआरसी temDelegate को शून्य पर सेट करेगा। हालांकि, टेक्स्ट फ़ील्ड के प्रतिनिधि अभी भी स्मृति को याद करने के लिए एक सूचक है, जिसे बाद में एआरसी द्वारा जारी किया जाता है। यही कारण है कि आपको खराब स्मृति पहुंच दुर्घटना मिली है।

डेल को अपनी कक्षा में स्थैतिक var के रूप में रखते हुए, इसे आपके ऐप रन चक्र के दौरान रखा जाएगा जब तक कि आप इसे शून्य पर सेट न करें। मुझे लगता है कि स्थैतिक डेल को कक्षा स्तर के सदस्य के रूप में रखना और एक सेटटर प्रदान करना बेहतर है ताकि आपको इसे जारी करना याद रखना चाहिए। कुछ ऐसा:

// in interface definition 
+(NumericTextFieldDelegate *) getDelegate; 
+(void) setDelegate:(id)newDel; 

// in implementation 
static NumericTextFieldDelegate* del; 

+(NumericTextFieldDelegate *) getDelegate { 
    @synchronized(del) { 
    if(del == nil) 
     del = [NumericTextFieldDelegate new]; 
    } 
    return del; 
} 

+(void) setDelegate:(id)newDel { 
    del = newDel; 
} 

वैसे, आप अपने पूर्व वर्कअराउंड कोड भी रख सकते हैं। आप प्रतिनिधि को वर्ग क्षेत्र के वर्ग में कक्षा सदस्य चर या संपत्ति के रूप में रख सकते हैं।

@interface myTextFieldContainer() { 
@proerpty (strong) id<UITextFieldDelegate> delHolder; 
... 
} 

@implementaion myTextFieldContainer { 
@sythysis delHolder = _delHodler; 
... 
self.delHolder = [NumericTextFieldDelegate new]; 
textFieldName.delegate = self.delHolder; 

ऊपर रणनीति का लाभ यह है कि आप के बारे में चिंता नहीं करता प्रतिनिधि जारी जब आपके विचार नियंत्रक चला गया है है।

1

बात यह है कि कोको (टच) में प्रतिनिधियों को आम तौर पर अप्रत्याशित किया जाता है। यह चक्र बनाए रखने से बचाता है। लेकिन इसका यह भी अर्थ है कि जब आप इसके साथ काम करते हैं तो उसे रिलीज़ करने के लिए ऑब्जेक्ट का संदर्भ रखने की आवश्यकता होती है - अन्यथा वस्तु केवल लीक हो जाती है। प्रतिनिधि पैटर्न इस पैटर्न में काम करता है।

कारण getDelegate विधि कार्य करता है क्योंकि प्रतिनिधि का संदर्भ स्थैतिक चर del में संग्रहीत है, जो ऑब्जेक्ट को ऑब्जेक्ट जारी करने से रोकता है।

+0

हां, मुझे पता है क्योंकि यह काम करता है ... मैंने खुद से कामकाज लिखा है। मैं समझ नहीं पा रहा हूं कि अगर एआरसी में मैं उस वस्तु को बरकरार नहीं रख सकता हूं कि किस तरह का असाइनमेंट काम नहीं करता है ... – aleroot

0

ठीक है, "क्यों" है, क्योंकि UITextField संपत्ति delegate घोषित किया जाता है के रूप में:

@property(nonatomic, assign) id<UITextFieldDelegate> delegate 

(class reference देखें।)

घोषित संपत्ति assign "सेटर सरल काम का उपयोग करता है" इसका मतलब है कि और इसलिए किसी भी मेमोरी प्रबंधन सुविधाओं को लागू नहीं करता है जैसे कि बनाए रखना (या इसे असाइन किए जाने पर रिलीज़ करें)। (The Objective-C Programming Language, Declared Properties देखें)

+0

हां, लेकिन क्यों एआरसी इसे "समझ" नहीं देती है? मुझे काम क्यों करना है? – aleroot

+0

यह समझ में आता है, लेकिन आपको अनुरोध किए गए सटीक परिणाम दे रहा है। यह आंकड़े बताता है कि शायद यह नहीं है कि आप ** ** चाहते हैं, हालांकि, आपको चेतावनी देता है। बेहतर सवाल यह होगा कि "ऐप्पल अपने प्रतिनिधियों के लिए असाइन क्यों करता है?"। इसे चक्र बनाए रखने से बचने के लिए करना है, मैं अनुमान लगाने के लिए उद्यम करना होगा। – lnafziger

1

मैं कक्षा के अज्ञात नए उदाहरण को क्यों निर्दिष्ट नहीं कर सकता? असाइनमेंट के बाद ऑब्जेक्ट स्वचालित रूप से क्यों जारी किया जाता है?

मुझे इस कामकाज की आवश्यकता क्यों है?

आप कक्षा का एक नया उदाहरण असाइन कर सकते हैं। लेकिन यह तुरंत जारी हो जाता है क्योंकि इसका कोई मजबूत संदर्भ नहीं है - टेक्स्टफील्ड द्वारा केवल एक कमजोर (असुरक्षित अप्रत्याशित)।प्रतिनिधि जो पहले से उल्लिखित चक्रों को बनाए रखने के लिए है। और यही वही है जो चेतावनी आपको बता रही है। हालांकि मैं इस सिंगलटन-जैसी पैटर्न का उपयोग नहीं करता। बस अपने प्रतिनिधि ऑब्जेक्ट के लिए एक मजबूत संपत्ति जोड़ें और उस संपत्ति मूल्य को अपने टेक्स्टफील्ड के प्रतिनिधि के रूप में असाइन करें।

@property (nonatomic,strong) MyDelegateObject delegateObject; 

Self.delegateObject = [MyDelegateObject new]; 
Textfield.delegate = self.delegateObject; 
संबंधित मुद्दे