2010-06-10 19 views
28

मैंने इन लाइनों को डेमो प्रोजेक्ट में देखा, लेकिन मुझे समझ में नहीं आया कि ऐसा क्यों हुआ।"willChangeValueForKey" और "didChangeValueForKey" का उपयोग कब करें?

[self willChangeValueForKey:@"names"]; 
[self didChangeValueForKey:@"names"]; 

इसे चेंजेंजवेल्यूफोर्की के तुरंत बाद किया गया चेंजवेल्लू फोर्की कहा जाता है। क्या यह कोई समझ में आता है?

इसके अलावा, इन दो विधियों को कॉल करने का सही समय कब होना चाहिए? बहुत बहुत धन्यवाद !! :)

उत्तर

48

यह वास्तव में एक विरोधी पैटर्न है। आपको किसी भी हस्तक्षेप वास्तविक संपत्ति परिवर्तन के बिना -willChangeValueForKey: पर -didChangeValueForKey: पर कॉल नहीं करना चाहिए। कुछ मामलों में, ऐसा करने से आपके कोड में कहीं और केवीओ समस्याओं को मुखौटा कर सकते हैं और पर्यवेक्षकों को प्रश्न में संपत्ति से संबंधित अपने राज्य को अपडेट करने के लिए मजबूर कर सकते हैं। आखिरकार, आप (या आपके द्वारा उद्धृत उदाहरण के लेखक) को शेष कोड को ठीक करना चाहिए ताकि यह विरोधी पैटर्न अनावश्यक हो।

-will|didChangeValueForKey: का सही उपयोग तब होता है जब आप केवीसी-अनुपालन एक्सेसर्स/सेटर्स का उपयोग किये बिना किसी संपत्ति को संशोधित कर रहे हैं जैसे कि केवीओ तंत्र में बदलाव की सूचना नहीं होगी। एक काल्पनिक उदाहरण के लिए, एक विशेषता सीधे के लिए समर्थन उदाहरण चर को संशोधित करने पर विचार करें:

@interface Foo 
{ 
    int bar; 
} 
@end 

@implementation Foo 
- (void)someMethod 
{ 
    bar = 10; 
} 
@end 

KVO पर्यवेक्षकों कि bar संपत्ति में परिवर्तनों की सूचना के लिए पंजीकृत किया था -someMethod में bar करने के लिए परिवर्तन की अधिसूचना प्राप्त नहीं होता। KVO मशीनरी काम करने के लिए, आपको -someMethod को संशोधित कर सकते हैं:

- (void)someMethod 
{ 
    [self willChangeValueForKey:@"bar"]; 
    bar = 10; 
    [self didChangeValueForKey:@"bar"]; 
} 
बेशक

, यह एक @property घोषणा उपयोग करने के लिए बेहतर होगा और प्रयोग करने में KVC अनुरूप accessors/setters (या तो स्वयं कोडित या @synthesized), लेकिन यह एक विकसित उदाहरण है।

+0

आपको बहुत बहुत धन्यवाद! – Frost

+0

मैं एक ही मुद्दे पर भाग गया। ऐप्पल से केवीओ पर कुछ और है http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i – Dan

0
  • यदि आप मूल्य बदलने से ठीक पहले सामान करना चाहते हैं, तो WillChangeValueForKey का उपयोग करें।
  • यदि आप मूल्य बदलने के बाद सामान करना चाहते हैं, तो didChangeValueForKey का उपयोग करें।

संपादित करें: मुझे अनदेखा करते हैं, बहुत तेजी से पढ़ रहा था - बैरी सही :-)

1

उन मैन्युअल कुंजी मान अवलोकन को नियंत्रित करने के साथ क्या करना है। आम तौर पर सिस्टम इसका ख्याल रखता है लेकिन ये आपको कुछ नियंत्रण की अनुमति देता है। here का उपयोग कब और कैसे करें, यह समझने के लिए इस दस्तावेज़ को देखें।

1

बैरी के साथ सहमत हैं। मैं बस एक ही समस्या से मिलता हूं। यहां उन दो तरीकों का उपयोग करने का मामला है। मैंने एक पठनीय संपत्ति घोषित की। इसलिए मैं मूल्य बदलने के लिए संपत्ति के एक्सेसर का उपयोग नहीं कर सकता।

@property (nonatomic, readonly) BOOL var; 

मैं "var" को बदलना चाहते हैं, मैं इन दोनों तरीकों मैन्युअल कॉल करने के लिए की जरूरत है। अन्यथा, पर्यवेक्षकों को अधिसूचित नहीं किया जाएगा।

self willChangeValueForKey:@"var"]; 
var = YES; 
[self didChangeValueForKey:@"var"]; 
+0

var = YES जीता ' टी संकलन। क्या आपका मतलब self.var = हाँ है (जो भी पढ़ने के साथ संकलित नहीं होगा)? यदि आपका मतलब _var = हाँ है, जो संकलित होगा, लेकिन चूंकि आप जेनरेट किए गए सेटर का उपयोग नहीं कर रहे हैं, इसलिए मैं आश्चर्यचकित नहीं हूं/किया गया चेंज को कॉल नहीं किया जाता है। मैं self.var = हाँ बिना पढ़ने के उपयोग करेंगे। –

+0

हां। मेरा मतलब _var = हाँ है। मेरा मामला यह है कि मैन्युअल रूप से सूचित करने के लिए Will/didChange कॉल का उपयोग कैसे करें। – yibuyiqu

-3

जुलाई 2013 के इस पोस्ट कर रहा है, और यह अब होगा/didChangeValueForKey कॉल करने के लिए आवश्यक हो रहा है। ऐसा लगता है कि आपके पास कस्टम सेटर है, भले ही स्वचालित रूप से देखभाल की जाए।

+0

होगा/किया जाएगाChangeValueForKey पर्यवेक्षकों को सूचित करने के लिए अभी भी जरूरी है जब एक मूल्य * सेटर्स के बिना * बदलता है। –

9

केवीओ गुणों के लिए कस्टम सेटर्स के साथ सही ढंग से काम करेगा; एनएसओब्जेक्ट-व्युत्पन्न कक्षाओं के लिए यह हमेशा मामला रहा है। रनटाइम मशीनरी प्रासंगिक सेटर विधि के आविष्कार की तलाश करती है, और सेटटर को निष्पादित करने से पहले "willChangeValueForKey" को स्पष्ट रूप से कॉल करती है, फिर सेटर पूर्ण होने के बाद निहित रूप से "didChangeValueForKey" को कॉल करता है।

यदि आप केवीओ अधिसूचनाओं पर अधिक सुदृढ़ नियंत्रण चाहते हैं तो आप इस स्वचालित व्यवहार को अक्षम कर सकते हैं। जैसा ऊपर बताया गया है, केवल वही गुण जिनके मूल्य आप बैकिंग इवर को संशोधित करके बदलते हैं, या जिनके मूल्य गणना द्वारा व्युत्पन्न होते हैं, वे स्थान हैं जहां आप मैन्युअल सूचनाओं का उपयोग करेंगे (हालांकि एक तंत्र है, keyPathsAffectingValueFor, जहां आप रनटाइम बता सकते हैं कि किसी संपत्ति का मूल्य किसी अन्य संपत्ति के परिवर्तन पर निर्भर होता है, और यह परिवर्तन अधिसूचना को उपयुक्त के रूप में भेज देगा।) प्रति-संपत्ति के आधार पर स्वचालित व्यवहार को अक्षम करने के लिए, आप स्वचालित रूप से कक्षा विधि + (BOOL) डालते हैं NotifiesObserversOf और वापस नहीं ।

मैं अक्सर स्वचालित केवीओ अधिसूचनाओं को अक्षम करता हूं, क्योंकि मुझे पता चला है कि एक सेटर का आह्वान करते समय एक केवीओ अधिसूचना उत्पन्न होती है, भले ही संपत्ति का मूल्य उसके वर्तमान मूल्य (जैसे कोई परिवर्तन नहीं) के समान सेट किया जा रहा हो। मैं दक्षता की खातिर व्यर्थ अधिसूचना को दबाने के लिए चाहते हैं:

+ (BOOL)automaticallyNotifiesObserversOfMyProperty 
{ 
    return NO; 
} 

- (void)setMyProperty:(NSInteger)myProperty 
{ 
    if(_myProperty != myProperty) 
    { 
    [self willChangeValueForKey:@"myProperty"]; 
    _myProperty = myProperty; 
    [self didChangeValueForKey:@"myProperty"]; 
    } 
} 

एक अच्छी चर्चा NSKeyValueObserving.h शीर्षक में पाया जा सकता है, कि आप Cmd + विधि के नाम "willChangeValueForKey" और "didChangeValueForKey पर क्लिक करके नेविगेट कर सकते हैं "एक्सकोड में।

+0

क्या आपका मतलब है 'keyPathsFfValues ​​' की बजाय 'keyPathsAffectingValueFor'? – Mojo66

0

didChangeValueForKey: ओवरराइड करते समय वास्तव में सावधान रहें। सबसे अच्छी बात यह बिल्कुल नहीं है। लेकिन यदि आप करते हैं, तो सुनिश्चित करें कि आप super पर कॉल करें, अन्यथा आपके पास एक मेमोरी रिसाव होगा जैसा कि यहां प्रदर्शित किया गया है: https://github.com/jfahrenkrug/KVOMemoryLeak

संबंधित मुद्दे