2010-08-13 8 views
33

क्या किसी को पता है कि एक एनआईएसटीमर को रोकने के लिए सबसे अच्छा समय कब है जो टाइमर और नियंत्रक के बीच चक्र बनाए रखने से बचने के लिए UIViewController के अंदर संदर्भ आयोजित किया जाता है?चक्र को बनाए रखने से बचने के लिए UIViewController के अंदर NSTimer को अमान्य करने का सर्वोत्तम समय

यहां अधिक जानकारी में सवाल है: मेरे पास UIViewController के अंदर एक एनएसटीमर है।

statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateStatus) userInfo: nil repeats: YES]; 

ऊपर दृश्य नियंत्रक के लिए एक संदर्भ पकड़ करने के लिए टाइमर का कारण बनता है:

दृश्य नियंत्रक के viewDidLoad के दौरान, मैं टाइमर शुरू करते हैं। जहाँ मैं [statusTimer अमान्य] को कॉल कर दिया नियंत्रक के संदर्भ में जारी करने के लिए टाइमर के लिए मजबूर करने कर सकते हैं:

अब मैं अपने नियंत्रक (उदाहरण के लिए माता-पिता नियंत्रक विज्ञप्ति यह)

सवाल यह है कि जारी करने के लिए करना चाहते हैं?

मैंने इसे ViewDidUnload में डालने का प्रयास किया, लेकिन जब तक दृश्य को स्मृति चेतावनी प्राप्त नहीं होती तब तक इसे निकाल दिया नहीं जाता है, इसलिए एक अच्छी जगह नहीं है। मैंने dealloc की कोशिश की, लेकिन जब तक टाइमर जीवित रहता है तब तक dealloc कभी नहीं कहा जाएगा (चिकन & अंडा समस्या)।

कोई अच्छा सुझाव?

+0

के लिए काम किया है टाइमर में दृश्य नियंत्रक बनाए रखने के लिए कोई जरूरत नहीं है। वीसी को टाइमर का मालिक होना चाहिए, जैसा कि किसी अन्य ऑब्जेक्ट की तरह होगा, और उपयुक्त होने पर इसे नष्ट कर देना चाहिए। – logancautrell

+0

@logancautrell, आपके पास एक अच्छा बिंदु है, लेकिन 'एनएसटीमर' आपके द्वारा पारित लक्ष्य को बरकरार रखता है और इसे बदला नहीं जा सकता है। (कुछ जवाब इस बात के बारे में सुझाव देने और काम करने के तरीकों का सुझाव देते हैं।) –

+0

यिक्स, मैं उस समस्या को देखता हूं जिसमें आप चल रहे हैं। एक विकल्प है कि एक सहायक वस्तु को जोड़ना जो आपके वीसी और टाइमर दोनों के पास है। – logancautrell

उत्तर

21
  1. आप , द्वारा के साथ शुरू हो जैसे चक्र बनाए रखने से बच सकते हैं, टाइमर लक्ष्य StatusUpdate ऑब्जेक्ट पर जो आपके नियंत्रक के लिए एक गैर-बनाए रखा (कमजोर) संदर्भ रखता है, या StatusUpdater जो आपके नियंत्रक के सूचक के साथ प्रारंभ होता है, उसके लिए एक कमजोर संदर्भ रखता है, और आपके लिए टाइमर सेट करता है।

    • आप दृश्य -willMoveToWindow: में टाइमर रोक जब लक्ष्य विंडो nil है -viewDidDisappear: में (जो -viewDidDisappear: कि आपके द्वारा प्रदान करने के लिए प्रति एक संभाल चाहिए) के साथ ही हो सकता था। इसका मतलब है कि आपका विचार आपके नियंत्रक में वापस आ रहा है; आप नियंत्रक को -view:willMoveToWindow: संदेश भेजकर या अधिसूचना पोस्ट करके टाइमर को पकड़ने के लिए पहुंचने से बच सकते हैं, अगर आप परवाह करते हैं।

    • संभवतः, आप खिड़की से दृश्य को हटाने के कारण हैं, इसलिए आप देख सकते हैं कि रेखा को उस रेखा के साथ टाइमर को रोकने के लिए एक लाइन जोड़ें जो दृश्य को उजागर करता है।

    • आप एक गैर-दोहराने वाले टाइमर का उपयोग कर सकते हैं। जैसे ही यह आग लगती है, यह अमान्य हो जाएगी। फिर आप कॉलबैक में परीक्षण कर सकते हैं कि कोई नया गैर-दोहराने वाला टाइमर बनाया जाना चाहिए, और यदि ऐसा है, तो इसे बनाएं। अवांछित बनाए रखने चक्र तब केवल अगली आग की तारीख तक टाइमर और नियंत्रक जोड़ी रखेगा। 1 सेकंड की आग की तारीख के साथ, आपको चिंता करने की ज़रूरत नहीं होगी।

हर सुझाव लेकिन पहले बनाए रखने के चक्र के साथ रहते हैं और उचित समय पर इसे तोड़ने के लिए एक रास्ता है। पहला सुझाव वास्तव में बनाए रखने चक्र से बचाता है।

+0

के बारे में कुछ और कोड पोस्ट कर सकते हैं, मैं एक गैर-दोहराना टाइमर का उपयोग करना पसंद करता हूं और कॉलबैक में पुनर्निर्माण करता हूं। –

+0

मुझे लगता है कि 'viewWillMovetoWindow:' का उपयोग करना कस्टम व्यू क्लास का उपयोग करते समय सबसे अच्छा समाधान है, जिसमें टाइमर होता है, और जब इसका उपयोग करने वाले व्यू कंट्रोलर (वीसी) में उस व्यू क्लास का संदर्भ नहीं होता है। उस मामले पर विचार करें जहां एक वीसी में गतिशील विचार आरंभ किए जाते हैं; वीसी के पास व्यू क्लास को अपने टाइमर को अमान्य करने के लिए कोई स्पष्ट तरीका नहीं है जब 'व्यूविल डिस्प्लेयर:' कहा जाता है। यह अपने विचारों के माध्यम से फिर से शुरू हो सकता है और इसकी दृश्य कक्षा पर 'क्लीनअप' विधि बना सकता है या 'एनएसएनोटिफिकेशन' का उपयोग कर सकता है, लेकिन मुझे लगता है कि 'willMoveToWindow:' सबसे साफ है। ऐसा न करें कि दोहराए जाने वाले टाइमर सुझाव यहां काम करेंगे। –

+0

टाइमर को अमान्य करने के लिए 'dealloc' एक अच्छी जगह क्यों नहीं है? –

1

-viewDidDisappear विधि जो आप खोज रहे हैं हो सकता है। जब भी दृश्य छुपाया जाता है या खारिज कर दिया जाता है तो इसे बुलाया जाता है।

+0

लेकिन जब मैं अपने मूल दृश्य को छुपाता हूं तो देखेंडिडडिस्प्लेयर कभी भी कॉल नहीं किया जाता है: [self.view removeFromSuperview]। कोई अन्य सुझाव? – MyCSharpCorner

+0

इसके अलावा, जब एक UINavigationController के अंदर, viewDidDisappear को कॉल नहीं किया जाता है, इसलिए मैं इसे रखने के लिए एक और सामान्य जगह ढूंढ रहा हूं। – MyCSharpCorner

+0

viewDidDisappear सही होगा अगर कोई इसे हमेशा पर भरोसा कर सकता है, दुर्भाग्य से यह –

3

आप - (void)viewDidDisappear:(BOOL)animated साथ कोशिश कर सकते हैं और फिर आप इसे फिर से - (void)viewDidAppear:(BOOL)animated

More here

+0

मामला नहीं है जब UINavigationController के अंदर, viewDidDisappear को कॉल नहीं किया जाता है, इसलिए मैं इसे रखने के लिए एक और सामान्य जगह ढूंढ रहा हूं, जब भी मैं [self.view removeFromSuperview] का उपयोग करके दृश्य को छुपाएं, viewDidDisappear को या तो नहीं कहा जाता है। – MyCSharpCorner

+0

यूआईएनएविगेशन नियंत्रक के अंदर आपका क्या मतलब है। जब आप इसे पॉप आउट करते हैं? क्या आप – vodkhang

0

में सत्यापित करना चाहिए मैं वास्तव में इसी कारण एक "कमजोर संदर्भ" वर्ग लिखा था। यह NSObject subclasses, लेकिन आगे सभी विधियों कि NSObject एक लक्ष्य वस्तु का समर्थन नहीं करता है। टाइमर कमजोर पड़ता है, लेकिन कमजोर अपने लक्ष्य को बरकरार नहीं रखता है, इसलिए कोई बरकरार चक्र नहीं है।

लक्ष्य कॉल [कमजोर स्पष्ट] और [टाइमर अमान्य] या तो डेलोक में। Icky, है ना?

(अगले स्पष्ट बात अपनी खुद की घड़ी वर्ग है कि आप के लिए यह सब संभालती लिखने के लिए। है)

-3

आप दृश्य नियंत्रक

उदाहरण के लिए

की dealloc समारोह में इस कोड लिख सकते हैं।

-(void)dealloc 
{ 
    if([statusTimer isValid]) 
    { 
     [statusTimer inValidate]; 
     [statustimer release]; 
     statusTimer = nil; 
    } 
} 

इस तरह statustimer के संदर्भ काउंटर स्वचालित रूप से 1 & से घटती होगा भी आबंटित स्मृति पर डेटा भी

भी मिटा देगा आप

+3

-1 समस्या यह है कि 'dealloc' कभी नहीं बुलाया जाएगा क्योंकि' एनएसटीमर ''UIViewController' को जीवित रख रहा है। –

-1

मैं था - (void)viewDidDisappear:(BOOL)animated समारोह में इस कोड लिख सकते हैं बिल्कुल वही समस्या और अंत में मैंने व्यू कंट्रोलर की रिलीज विधि को ओवरराइड करने का निर्णय लिया, ताकि बनाए रखने के विशेष मामले को 2 और मेरा टाइमर चल रहा हो। यदि टाइमर नहीं चल रहा था तो इससे रिलीज गिनती शून्य हो जाएगी और फिर डेलोक कॉल करें।

- (oneway void) release { 
    // Check for special case where the only retain is from the timer 
    if (bTimerRunning && [self retainCount] == 2) { 
     bTimerRunning = NO; 
     [gameLoopTimer invalidate]; 
    } 
    [super release]; 
} 

मैं क्योंकि यह सरल और एक वस्तु के भीतर समझाया, जैसे कि, देखें नियंत्रक और इसलिए डिबग करने के लिए आसान रहता है इस दृष्टिकोण पसंद करते हैं। हालांकि, मुझे बरकरार/रिलीज श्रृंखला के साथ मिलना पसंद नहीं है, लेकिन मुझे इसके चारों ओर एक रास्ता नहीं मिल रहा है।

आशा है कि इससे मदद मिलती है और यदि आपको बेहतर दृष्टिकोण मिल जाए तो इसे भी सुनना अच्छा लगेगा।

डेव

संपादित करें: किया जाना चाहिए था - (oneway शून्य)

5

एक तरह से चारों ओर यह NSTimer अपने UIViewController के लिए एक कमजोर संदर्भ पकड़ बनाने के लिए है।

#import <Foundation/Foundation.h> 

@interface WeakRefClass : NSObject 

+ (id) getWeakReferenceOf: (id) source; 

- (void)forwardInvocation:(NSInvocation *)anInvocation; 

@property(nonatomic,assign) id source; 

@end 

@implementation WeakRefClass 

@synthesize source; 

- (id)init{ 
    self = [super init]; 
// if (self) { 
// } 
    return self; 
} 

+ (id) getWeakReferenceOf: (id) _source{ 

    WeakRefClass* ref = [[WeakRefClass alloc]init]; 
    ref.source = _source; //hold weak reference to original class 

    return [ref autorelease]; 
} 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 
    return [[self.source class ] instanceMethodSignatureForSelector:aSelector]; 
} 

- (void)forwardInvocation:(NSInvocation *)anInvocation 
{ 
    [anInvocation invokeWithTarget:self.source ]; 

} 

@end 

और आप इस तरह इसका इस्तेमाल:

statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: [WeakRefClass getWeakReferenceOf:self] selector: @selector(updateStatus) userInfo: nil repeats: YES]; 

आपका dealloc विधि कहा जाता हो जाता है (पहले के विपरीत) और मैं एक वर्ग है कि आपके वस्तु के लिए एक कमजोर संदर्भ रखती है और कि कॉल अग्रेषित बनाया इसके अंदर तुम सिर्फ फोन:

[statusTimer invalidate]; 
+0

इसे अधिक वोट प्राप्त करना चाहिए। – Mustafa

0

timer.REPEAT YES पर सेट है, टाइमर (जैसे दृश्य नियंत्रक या दृश्य) के मालिक पुनः आवंटित की जाती नहीं की जाएगी जब तक टाइमर invalida है टेड।

इस प्रश्न का समाधान आपके टाइमर को रोकने के लिए कुछ ट्रिगर बिंदु ढूंढना है।

उदाहरण के लिए, मैं एक टाइमर एक दृश्य में एनिमेटेड GIF छवियों खेलने के लिए शुरू करते हैं, और ट्रिगर बिंदु होगा:

  1. जब दृश्य superview में जोड़ा जाता है, टाइमर शुरू
  2. जब

    : देखने superview से निकाल दिया जाता, टाइमर

तो मैं UIView की तरह के रूप में willMoveToWindow: विधि का चयन रोक 10

- (void)willMoveToWindow:(UIWindow *)newWindow { 
    if (self.animatedImages && newWindow) { 
     _animationTimer = [NSTimer scheduledTimerWithTimeInterval:_animationInterval 
      target:self selector:@selector(drawAnimationImages) 
      userInfo:nil repeats:YES]; 
    } else { 
     [_animationTimer invalidate]; 
     _animationTimer = nil; 
    } 
} 

यदि आपका टाइमर व्यू कंट्रोलर के स्वामित्व में है, तो शायद viewWillAppear: और viewWillDisappear: टाइमर शुरू करने और रोकने के लिए एक अच्छी जगह है।

1

रद्द टाइमर के अंदर - (शून्य) viewWillDisappear: (bool) एनिमेटेड मुझे

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

  • कोई संबंधित समस्या नहीं^_^