मैं कैसे बता सकता हूं कि किसी वस्तु में मुख्य मूल्य पर्यवेक्षक संलग्न है


142

यदि आप हटाने के लिए ऑब्जेक्टिव c ऑब्जेक्ट को बता देते हैं: एक मुख्य पथ के लिए और वह मुख्य पथ पंजीकृत नहीं किया गया है, तो यह sads को क्रैक करता है। पसंद -

'कुंजी पथ "KeyPath "के लिए एक पर्यवेक्षक को नहीं हटा सकता क्योंकि यह पर्यवेक्षक के रूप में पंजीकृत नहीं है।'

क्या यह निर्धारित करने का कोई तरीका है कि किसी ऑब्जेक्ट में एक पंजीकृत पर्यवेक्षक है, इसलिए मैं ऐसा कर सकता हूं

if (object has observer){
  remove observer
}
else{
  go on my merry way
}

मैं इस परिदृश्य में iOS 8 पर एक पुराने ऐप को अपडेट कर रहा था, जहां एक व्यू कंट्रोलर डील किया जा रहा था और "नॉट रिमूव" अपवाद को फेंक रहा था। मैंने सोचा था कि कॉल addObserver:करके viewWillAppear:और removeObserver:अंदर से viewWillDisappear:, कॉल को सही तरीके से जोड़ा गया था। मुझे एक त्वरित समाधान करना है इसलिए मैं कोशिश-कैच समाधान को लागू करने जा रहा हूं और आगे के कारणों की जांच करने के लिए एक टिप्पणी छोड़ दूंगा।
bneely

मैं बस कुछ इसी तरह से काम कर रहा हूं और मुझे लगता है कि मुझे अपने डिजाइन को और अधिक गहराई से देखने और इसे समायोजित करने की आवश्यकता है ताकि मुझे पर्यवेक्षक को फिर से हटाने की आवश्यकता न हो।
बोगदान

इस उत्तर में सुझाए गए बूल मूल्य का उपयोग करना मेरे लिए सबसे अच्छा काम किया: stackoverflow.com/a/37641685/4833705
लांस सामरिया

जवाबों:


315

अपने रिमूवर ऑबस्वर कॉल के चारों ओर एक ट्राई कैच डालें

@try{
   [someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
   //do nothing, obviously it wasn't attached because an exception was thrown
}

12
1+ अच्छा जवाब, मेरे लिए काम किया और मैं संपादित होने से पहले आपके शेख़ी से सहमत हूँ।
राबर्ट

25
हटाए गए शेख़ी के लिए upvoted है कि मैं सबसे अधिक संभावना से सहमत हूँ।
बेन गोटो

12
यहाँ कोई अन्य सुरुचिपूर्ण समाधान नहीं है? यह प्रति उपयोग में कम से कम 2ms लेता है ... इसे एक टेबलव्यू में कल्पना करें
João Nunes

19
डाउनवोटेड क्योंकि आप यह कहने में चूक रहे हैं कि यह उत्पादन कोड के लिए असुरक्षित है और किसी भी समय विफल होने की संभावना है। कोको में फ्रेमवर्क कोड के माध्यम से अपवाद उठाना कोई विकल्प नहीं है।
निकोलाई रुहे

6
स्विफ्ट 2.1 में इस कोड का उपयोग कैसे करें। do {try self.playerItem? .removeObserver (स्वयं, forKeyPath: "स्थिति")} NSError के रूप में त्रुटि को पकड़ने दें {print (error.localizedDescription)} चेतावनी प्राप्त करना।
विपुलक 617

37

असली सवाल यह है कि आप यह नहीं जानते कि आप इसे देख रहे हैं या नहीं।

यदि आप ऑब्‍जेक्‍ट की कक्षा में ऐसा कर रहे हैं, तो रोकें। जो कुछ भी इसे देख रहा है वह उम्मीद करता है कि इसका अवलोकन किया जाए। यदि आप पर्यवेक्षक की सूचनाओं को उसके ज्ञान के बिना काट देते हैं, तो चीजों को तोड़ने की अपेक्षा करें; अधिक विशेष रूप से, पर्यवेक्षक की स्थिति को बासी जाने की अपेक्षा करें क्योंकि यह पूर्व-देखी गई वस्तु से अपडेट प्राप्त नहीं करता है।

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

ऑब्जर्वर के रूप में किसी ऑब्जेक्ट को जोड़ना और हटाना आमतौर पर ऑब्जर्वर की क्लास में होना चाहिए, और ऑब्जर्व्ड ऑब्जेक्ट में कभी नहीं।


14
केस का उपयोग करें: आप viewDidUnload में पर्यवेक्षकों को हटाना चाहते हैं, और डीलॉक में भी। यह उन्हें दो बार निकाल रहा है और अपवाद को फेंक देगा यदि आपका व्यूकंट्रोलर एक मेमोरी चेतावनी से अनलोड है, और फिर जारी भी किया गया है। आप इस परिदृश्य को संभालने का सुझाव कैसे देते हैं?
बंदगीजैसा

2
@bandejapaisa: मेरे जवाब में बहुत कुछ जो मैंने कहा है: ध्यान रखें कि मैं देख रहा हूं या नहीं और केवल यह देखने की कोशिश करूं कि क्या मैं हूं।
पीटर होसी

41
नहीं, यह एक दिलचस्प सवाल नहीं है। आपको इसका ध्यान नहीं रखना चाहिए; आपको डीललोक में सभी श्रोताओं को बस अपंजीकृत करने में सक्षम होना चाहिए, बिना परवाह किए कि क्या आप कोड पथ को हिट करने के लिए हुआ है जहां इसे जोड़ा गया था या नहीं। यह NSNotificationCenter के निष्कासन की तरह काम करना चाहिए, जो परवाह नहीं करता है यदि आपके पास वास्तव में एक है या नहीं। यह अपवाद केवल ऐसे कीड़े पैदा कर रहा है जहां कोई भी अन्यथा मौजूद नहीं होगा, जो खराब एपीआई डिजाइन है।
ग्लेन मेनार्ड

1
@GlennMaynard: जैसे मैंने उत्तर में कहा, “यदि आप पर्यवेक्षक के नोटिफिकेशन को बिना उसकी जानकारी के काट देते हैं, तो चीजों को तोड़ने की उम्मीद करें; अधिक विशेष रूप से, पर्यवेक्षक के राज्य को बासी जाने की अपेक्षा करें क्योंकि यह पूर्व-देखी गई वस्तु से अपडेट प्राप्त नहीं करता है। " प्रत्येक पर्यवेक्षक को अपना अवलोकन समाप्त करना चाहिए; ऐसा करने में विफलता आदर्श रूप से अत्यधिक दिखाई देनी चाहिए।
पीटर होसी

3
प्रश्न में कुछ भी अन्य कोड के पर्यवेक्षकों को हटाने के बारे में बात नहीं करता है ।
ग्लेन मेनार्ड

25

FWIW, [someObject observationInfo]लगता है nilअगर someObjectकोई पर्यवेक्षक नहीं है। हालाँकि, मुझे इस व्यवहार पर भरोसा नहीं होगा, क्योंकि मैंने इसे दस्तावेज के रूप में नहीं देखा है। इसके अलावा, मुझे नहीं पता कि observationInfoविशिष्ट पर्यवेक्षकों को प्राप्त करने के लिए कैसे पढ़ना है।


क्या आप जानते हैं कि मैं एक विशिष्ट पर्यवेक्षक को कैसे पुनः प्राप्त कर सकता हूं? objectAtIndex:वांछित परिणाम नहीं देता है।)
एमींटास

1
@MattDiPasquale क्या आप जानते हैं कि मैं कोड में अवलोकनइन्फो कैसे पढ़ सकता हूँ? प्रिंट में यह ठीक निकल रहा है, लेकिन यह शून्य को इंगित करता है। मुझे इसे कैसे पढ़ना चाहिए?
नीरज

अवलोकनइन्फो Xcode के डिबगिंग पेपर (शीर्षक में "जादू" के साथ कुछ) में प्रलेखित विधि डिबगिंग है। आप इसे देखने की कोशिश कर सकते हैं। मैं बता सकता हूं कि अगर आपको यह जानने की जरूरत है कि क्या कोई आपकी वस्तु को देख रहा है - तो आप कुछ गलत कर रहे हैं। अपने आर्किटेक्चर और तर्क को पुनर्विचार करें। इसे कठिन तरीके से सीखें।)
ईमंतस

स्रोत:NSKeyValueObserving.h
nefarianblack

प्लस 1 एक हास्यपूर्ण मृत अंत के लिए लेकिन अभी भी कुछ हद तक मददगार जवाब है
विल वॉन उलरिच

4

ऐसा करने का एकमात्र तरीका यह है कि जब आप एक पर्यवेक्षक जोड़ते हैं तो एक झंडा लगाना है।


3
आप हर जगह BOOLs के साथ अंत करते हैं, बेहतर अभी भी एक KVO आवरण वस्तु बनाते हैं जो पर्यवेक्षक को जोड़ने और इसे हटाने का काम करता है। यह सुनिश्चित कर सकता है कि आपका पर्यवेक्षक केवल एक बार हटा दिया जाए। हमने इस तरह से एक वस्तु का उपयोग किया है, और यह काम करता है।
बंदगीजैसा

महान विचार यदि आप हमेशा नहीं देख रहे हैं।
आंद्रे साइमन

4

जब आप किसी ऑब्जर्वर को किसी ऑब्जेक्ट में जोड़ते हैं तो आप उसे NSMutableArrayइस तरह जोड़ सकते हैं :

- (void)addObservedObject:(id)object {
    if (![_observedObjects containsObject:object]) {
        [_observedObjects addObject:object];
    }
}

यदि आप वस्तुओं को संरक्षित करना चाहते हैं, तो आप कुछ कर सकते हैं:

for (id object in _observedObjects) {
    if ([object isKindOfClass:[MyClass class]]) {
        MyClass *myObject = (MyClass *)object;
        [self unobserveMethod:myObject];
    }
}
[_observedObjects removeAllObjects];

याद रखें, यदि आप किसी एकल वस्तु का अनावरण करते हैं, तो उसे _observedObjectsसरणी से हटा दें :

- (void)removeObservedObject:(id)object {
    if ([_observedObjects containsObject:object]) {
        [_observedObjects removeObject:object];
    }
}

1
यदि यह एक बहु लड़ी पिरोया हुआ संसार में होता है, तो आपको यह सुनिश्चित करने की आवश्यकता है कि आपका सरणी थ्रेडसेफ़ है
श्रुतिम

आप किसी ऑब्जेक्ट का एक मजबूत संदर्भ रख रहे हैं, जो सूची में हर बार एक ऑब्जेक्ट जोड़े जाने पर बनाए रखने की संख्या को बढ़ाएगा और तब तक नहीं हटाया जाएगा जब तक कि इसका संदर्भ सरणी से हटा नहीं दिया जाता। मैं कमजोर संदर्भों को रखने के लिए NSHashTable/ उपयोग करना पसंद करूंगा NSMapTable
अतुलखत्री

3

मेरी राय में - यह रिटेनकाउंट तंत्र के समान काम करता है। आप निश्चित नहीं हो सकते हैं कि वर्तमान समय में आपके पास आपका पर्यवेक्षक है। यहां तक ​​कि अगर आप जांच करते हैं: self.observationInfo - आप सुनिश्चित नहीं कर सकते हैं कि आपके पास भविष्य में पर्यवेक्षक होंगे / नहीं होंगे।

रिटेनकाउंट की तरह । हो सकता है कि अवलोकनइन्फो विधि बिल्कुल बेकार की तरह नहीं है, लेकिन मैं इसे केवल डिबग उद्देश्यों में उपयोग करता हूं।

इसलिए परिणाम के रूप में - आपको बस इसे स्मृति प्रबंधन की तरह करना होगा। यदि आपने एक पर्यवेक्षक जोड़ा है - इसे तब हटा दें जब आपको इसकी आवश्यकता न हो। जैसे viewWillAppear / viewWillDisappear आदि विधियों का उपयोग करना। उदाहरण के लिए:

-(void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self addObserver:nil forKeyPath:@"" options:NSKeyValueObservingOptionNew context:nil];
}

-(void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self removeObserver:nil forKeyPath:@""];
}

और आपको कुछ विशिष्ट चेक की आवश्यकता है - अपनी खुद की कक्षा को लागू करें जो पर्यवेक्षकों की एक सरणी को संभालती है और इसे आपके चेक के लिए उपयोग करती है।


[self removeObserver:nil forKeyPath:@""]; इससे पहले जाने की जरूरत है: [super viewWillDisappear:animated];
जोशुआ हार्ट

@JoshuaHart क्यों?
चतुर्थी

क्योंकि यह एक आंसू विधि (डीललॉक) है। जब आप किसी प्रकार की छेड़छाड़ विधि को ओवरराइड करते हैं, तो आप सुपर लास्ट कहते हैं। जैसे:- (void) setupSomething { [super setupSomething]; … } - (void) tearDownSomething { … [super tearDownSomething]; }
यहोशू हार्ट

viewWillDisapear एक आंसू डाउन विधि नहीं है और इसका कोई संबंध नहीं है। यदि आप नेविगेशन स्टैक के लिए आगे बढ़ते हैं, तो viewWillDisapear कहा जाएगा, लेकिन आपका दृश्य स्मृति में रहेगा। मैं देखता हूं कि आप सेटअप / फाड़ के तर्क के साथ कहां जा रहे हैं, लेकिन यहां ऐसा करने से कोई वास्तविक लाभ नहीं होगा। आप सुपर से पहले हटाने को जगह देना चाहेंगे, यदि आपके पास बेस क्लास में कुछ तर्क हैं, जो वर्तमान पर्यवेक्षक के साथ संघर्ष कर सकता है।
quarezz

3

[someObject observationInfo]nilयदि कोई पर्यवेक्षक नहीं है तो वापस लौटें ।

if ([tableMessage observationInfo] == nil)
{
   NSLog(@"add your observer");
}
else
{
  NSLog(@"remove your observer");

}

Apple डॉक्स के अनुसार: अवलोकनइन्फो एक ऐसे पॉइंटर को लौटाता है जो रिसीवर के साथ पंजीकृत सभी पर्यवेक्षकों के बारे में जानकारी की पहचान करता है।
फ्रेडरिक


2

पर्यवेक्षक पैटर्न का पूरा बिंदु एक अवलोकन वर्ग को "सील" करने की अनुमति देना है - यह जानने या देखभाल करने के लिए नहीं कि क्या यह मनाया जा रहा है। आप स्पष्ट रूप से इस पैटर्न को तोड़ने की कोशिश कर रहे हैं।

क्यों?

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


10
वह पूछ रहा है कि श्रोता यह कैसे पता लगा सकता है कि क्या वह किसी चीज़ को सुन रहा है, न कि किस तरह से ऑब्जर्व किया जा रहा है, यह पता लगा सकता है कि क्या देखा जा रहा है।
ग्लेन मेनार्ड

1

मैं इस बात का प्रशंसक नहीं हूं कि कैच सॉल्यूशन का प्रयास करूं, इसलिए मैं ज्यादातर समय यही करता हूं कि मैं उस क्लास के अंदर एक विशिष्ट अधिसूचना के लिए एक सदस्यता और सदस्यता समाप्त विधि बनाऊं। उदाहरण के लिए, ये दो विधियाँ ऑब्जेक्ट को वैश्विक कीबोर्ड अधिसूचना के अधीन या अनसब्सक्राइब करती हैं:

@interface ObjectA : NSObject
-(void)subscribeToKeyboardNotifications;
-(void)unsubscribeToKeyboardNotifications;
@end

उन तरीकों के अंदर, मैं एक निजी संपत्ति का उपयोग करता हूं जो सदस्यता स्थिति के आधार पर सही या गलत पर सेट होती है:

@interface ObjectA()
@property (nonatomic,assign) BOOL subscribedToKeyboardNotification
@end

@implementation

-(void)subscribeToKeyboardNotifications {
    if (!self.subscribedToKeyboardNotification) {
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil];
        self.subscribedToKeyboardNotification = YES;
    }
}

-(void)unsubscribeToKeyboardNotifications {
    if (self.subscribedToKeyboardNotification) {
        [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
        self.subscribedToKeyboardNotification = NO;
    }
}
@end

0

एडम के जवाब के अलावा मैं इस तरह मैक्रो का उपयोग करने के लिए सुझाव देना चाहूंगा

#define SafeRemoveObserver(sender, observer, keyPath) \
@try{\
   [sender removeObserver:observer forKeyPath:keyPath];\
}@catch(id anException){\
}

उपयोग का उदाहरण

- (void)dealloc {
    SafeRemoveObserver(someObject, self, somePath);
}

1
यह कितना पागल है कि यह एक अपवाद फेंकता है? अगर यह कुछ भी नहीं है तो कुछ भी नहीं करता है?
अरण मुलहोलैंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.