जबकि UIScrollView
(या एक व्युत्पन्न वर्ग) स्क्रॉल कर रहा है, ऐसा लगता है जैसे NSTimers
कि सभी समाप्त हो रहे हैं जब तक स्क्रॉल समाप्त नहीं हो जाता है।
क्या इस से निकाल पाने के लिए कोई तरीका है? धागे? एक प्राथमिकता सेटिंग? कुछ भी?
जबकि UIScrollView
(या एक व्युत्पन्न वर्ग) स्क्रॉल कर रहा है, ऐसा लगता है जैसे NSTimers
कि सभी समाप्त हो रहे हैं जब तक स्क्रॉल समाप्त नहीं हो जाता है।
क्या इस से निकाल पाने के लिए कोई तरीका है? धागे? एक प्राथमिकता सेटिंग? कुछ भी?
जवाबों:
समाधान को लागू करने के लिए एक आसान और सरल तरीका है:
NSTimer *timer = [NSTimer timerWithTimeInterval:...
target:...
selector:....
userInfo:...
repeats:...];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
स्विफ्ट 3 का उपयोग करने वाले किसी के लिए भी
timer = Timer.scheduledTimer(timeInterval: 0.1,
target: self,
selector: aSelector,
userInfo: nil,
repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
timer = Timer(timeInterval: 0.1, target: self, selector: aSelector, userInfo: nil, repeats: true)
बजाय पहले कमांड के रूप में कॉल करना बेहतर होता है Timer.scheduleTimer()
, क्योंकि scheduleTimer()
टाइमर को रनलूप में जोड़ा जाता है, और अगली कॉल उसी रनअप में एक और जोड़ रही है लेकिन अलग मोड के साथ। एक ही काम दो बार मत करो।
यह स्विफ्ट वर्जन है।
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: aSelector, userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
यदि आप स्क्रॉल करते समय फायर करना चाहते हैं तो आपको एक और धागा और दूसरा रन लूप चलाना होगा; चूंकि घटना पाश के हिस्से के रूप में टाइमर संसाधित होते हैं, यदि आप अपने दृश्य स्क्रॉल करने में व्यस्त हैं, तो आप कभी भी टाइमर के आसपास नहीं पहुंचते हैं। यद्यपि अन्य थ्रेड्स पर चलने वाले टाइमर की पूर्ण / बैटरी जुर्माना इस मामले को संभालने के लायक नहीं हो सकती है।
किसी के लिए भी स्विफ्ट 4 का उपयोग करें:
timer = Timer(timeInterval: 1, target: self, selector: #selector(timerUpdated), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: .common)
tl; dr रनलूप स्क्रॉल कर रहा है ताकि यह किसी भी अधिक घटनाओं को संभाल न सके - जब तक कि आप मैन्युअल रूप से टाइमर सेट न करें ताकि यह तब भी हो सके जब रनअप टच घटनाओं को संभाल रहा हो। या एक वैकल्पिक समाधान का प्रयास करें और GCD का उपयोग करें
किसी भी iOS डेवलपर के लिए पढ़ना चाहिए। रनऑलॉप के माध्यम से अंततः बहुत सी चीजों को अंजाम दिया जाता है।
Apple के डॉक्स से व्युत्पन्न ।
एक रन लूप बहुत पसंद है इसका नाम लगता है। यह एक लूप है जो आपके धागे में प्रवेश करता है और आने वाली घटनाओं के जवाब में इवेंट हैंडलर चलाने के लिए उपयोग करता है
क्योंकि जब आप रन लूप चलाते हैं, तो टाइमर और अन्य आवधिक घटनाओं को वितरित किया जाता है, उस लूप को दरकिनार करने से उन घटनाओं का वितरण बाधित होता है। इस व्यवहार का विशिष्ट उदाहरण तब होता है जब आप लूप दर्ज करके और बार-बार आवेदन से घटनाओं का अनुरोध करके माउस-ट्रैकिंग रूटीन को लागू करते हैं। क्योंकि आपका कोड सीधे घटनाओं को हड़प रहा है, इसलिए एप्लिकेशन को उन घटनाओं को सामान्य रूप से भेजने देने के बजाय, सक्रिय माउस आपके माउस-ट्रैकिंग रूटीन से बाहर निकलने और आवेदन पर नियंत्रण वापस करने तक फायर करने में असमर्थ होगा।
यह कभी भी, हमारे लिए बिना सूचना के बहुत कुछ होता है। मेरा मतलब है कि हम टाइमर को 10: 10: 10: 00 पर सेट करते हैं, लेकिन रनअप एक घटना को अंजाम दे रहा है जो 10: 10: 10: 05 तक होती है, इसलिए टाइमर को 10: 10: 10: 06 निकाल दिया जाता है।
इसी तरह, अगर एक टाइमर जब हैंडलर रूटीन को निष्पादित करने के बीच में चलता है, तो टाइमर फायर करता है, टाइमर अपने हैंडलर रूटीन को लागू करने के लिए रन लूप के माध्यम से अगली बार इंतजार करता है। यदि रन लूप बिल्कुल नहीं चल रहा है, तो टाइमर कभी भी फायर नहीं करता है।
आप केवल एक बार या बार-बार ईवेंट उत्पन्न करने के लिए टाइमर कॉन्फ़िगर कर सकते हैं। एक दोहराई जाने वाली टाइमर अपने आप शेड्यूल किए गए फायरिंग समय के आधार पर स्वचालित रूप से फिर से शुरू होती है, न कि वास्तविक फायरिंग समय के आधार पर। उदाहरण के लिए, यदि एक टाइमर को एक विशेष समय पर और उसके बाद हर 5 सेकंड में आग लगने के लिए निर्धारित किया जाता है, तो निर्धारित गोलीबारी का समय हमेशा मूल 5 सेकंड के अंतराल पर गिर जाएगा, भले ही वास्तविक गोलीबारी का समय देरी हो। यदि फायरिंग के समय में इतनी देरी हो जाती है कि यह निर्धारित फायरिंग के समय में से एक या अधिक बार छूट जाता है, तो टाइमर को केवल एक बार छूटी हुई समयावधि के लिए निकाल दिया जाता है। मिस्ड अवधि के लिए फायरिंग के बाद, टाइमर को अगले निर्धारित फायरिंग समय के लिए पुनर्निर्धारित किया जाता है।
आप नहीं कर सकते। ओएस सिर्फ आपके लिए खुद को बदलता है। जैसे जब उपयोगकर्ता टैप करता है, तब मोड स्विच हो जाता है eventTracking
। जब उपयोगकर्ता नल समाप्त हो जाते हैं, तो मोड वापस चला जाता है default
। यदि आप चाहते हैं कि कुछ विशिष्ट मोड में चलाया जाए, तो यह आपके लिए सुनिश्चित है कि ऐसा होता है।
जब उपयोगकर्ता स्क्रॉल कर रहा है तो रन लूप मोड बन जाता है tracking
। RunLoop को गियर बदलने के लिए डिज़ाइन किया गया है। एक बार जब मोड सेट हो जाता है eventTracking
, तो यह घटनाओं को छूने के लिए प्राथमिकता देता है (याद रखें कि हमारे पास सीमित सीपीयू कोर है)। यह ओएस डिजाइनरों द्वारा एक वास्तुशिल्प डिजाइन है ।
डिफ़ॉल्ट रूप से टाइमर tracking
मोड पर शेड्यूल नहीं किए जाते हैं । वे इस पर निर्धारित हैं:
एक टाइमर बनाता है और इसे डिफ़ॉल्ट मोड में वर्तमान रन लूप पर शेड्यूल करता है।
scheduledTimer
नीचे इस करता है:
RunLoop.main.add(timer, forMode: .default)
यदि आप चाहते हैं कि आपका टाइमर स्क्रॉल करते समय काम करे तो आपको या तो करना होगा:
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self,
selector: #selector(fireTimer), userInfo: nil, repeats: true) // sets it on `.default` mode
RunLoop.main.add(timer, forMode: .tracking) // AND Do this
या बस करो:
RunLoop.main.add(timer, forMode: .common)
अंततः उपरोक्त में से एक करने का मतलब है कि आपका धागा स्पर्श घटनाओं से अवरुद्ध नहीं है । जो इसके बराबर है:
RunLoop.main.add(timer, forMode: .default)
RunLoop.main.add(timer, forMode: .eventTracking)
RunLoop.main.add(timer, forMode: .modal) // This is more of a macOS thing for when you have a modal panel showing.
आप अपने टाइमर के लिए जीसीडी का उपयोग करने पर विचार कर सकते हैं जो आपको लूप प्रबंधन के मुद्दों से अपने कोड को "ढाल" करने में मदद करेगा।
केवल उपयोग न करने के लिए:
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// your code here
}
बार-बार उपयोग के लिए:
DispatchSourceTimer का उपयोग करने का तरीका देखें
डैनियल जलकुट के साथ एक चर्चा से गहरी खुदाई:
प्रश्न: GCD (बैकग्राउंड थ्रेड्स) कैसे होता है जैसे कि बैकग्राउंड थ्रेड पर एक asyncAfter RunLoop के बाहर निष्पादित किया जाता है? इससे मेरी समझ यह है कि सब कुछ एक RunLoop के भीतर निष्पादित किया जाना है
जरूरी नहीं - प्रत्येक धागे में एक रन लूप हो, लेकिन शून्य हो सकता है यदि थ्रेड के निष्पादन "स्वामित्व" को समन्वित करने का कोई कारण नहीं है।
थ्रेड्स एक OS स्तर का खर्च है जो आपकी प्रक्रिया को कई समानांतर निष्पादन संदर्भों में अपनी कार्यक्षमता को विभाजित करने की क्षमता देता है। रन लूप्स एक फ्रेम-लेवल खर्च है जो आपको एक सिंगल थ्रेड को अलग करने की अनुमति देता है ताकि इसे कई कोड पाथ द्वारा कुशलता से साझा किया जा सके।
आमतौर पर यदि आप किसी ऐसी चीज़ को भेजते हैं, जो किसी थ्रेड पर चलती है, तो संभवत: इसमें कोई रन-अप नहीं होगा, जब तक कि कुछ ऐसे कॉल नहीं आएंगे, [NSRunLoop currentRunLoop]
जो किसी एक को बनाते हैं।
संक्षेप में, मोड मूल रूप से इनपुट और टाइमर के लिए एक फिल्टर तंत्र हैं