Re: [問題] 請問Cocoa程式要如何一直做同件事情?

看板MacDev作者 (電腦無法阻止人類做蠢事)時間16年前 (2008/05/12 19:30), 編輯推噓1(102)
留言3則, 1人參與, 最新討論串6/7 (看更多)
※ 引述《Dannier (貓尾巴~)》之銘言: : 不好意思小弟不才 : 研究了一下了解了一些NSRunLoop : 可是還是有問題 : 我想要按一個扭開始一直做某件事情 : 按另一個則停止 : 但我還是不知道要怎麼讓它停止NSRunLoop : 實在想不出辦法來 : 想要請教高手指點....感激不盡(躬) 把你的code刪掉了 同樣的事,我會用下面的做法: //Do it by Timer @interface MyObject: NSObject { NSTimer* myTimer; } - (IBAction)startTimer:(id)sender; - (IBAction)stopTimer:(id)sender; - (void)timerHandler:(NSTimer*)theTimer; - (void)myTask; @end @implementation MyObject - (IBAction)startTimer:(id)sender { //pseudo code //Start timer with repeat } - (IBAction)stopTimer:(id)sender { //Stop timer } - (void)timerHandler:(NSTimer*)theTimer { //do something before myTask if needed //call myTask //do something after myTask if needed } - (void)myTask { // What your want to repeat. } @end 或者是 //Do it by thread @interface MyObject: NSObject { BOOL isThreadRunning; NSLock* threadStateLock; } - (IBAction)startThread:(id)sender; - (IBAction)stopThread:(id)sender; - (void)myThread:(id)anObject; - (void)myTask; @end @implementation MyObject - (IBAction)startThread:(id)sender { //lock for changing thread state //set isThreadRunning YES //unlock //Start thread with function myThread. } - (IBAction)stopThread:(id)sender { //lock for changing thread state //set isThreadRunning NO //unlock } - (void)myThread:(id)anObject { //Declaring a local variable __isThreadRunning == NO //Do followings //{ // 1. do something before myTask if needed // 2. myTask // 3. do something after myTask if needed // 4. lock for loading thread state // __isThreadRunning = isThreadRunning // unlock //}while(__isThreadRunning == YES) } - (void)myTask { // What your want to repeat. } @end 我的原則是,儘量解說原理,而不提供實際的程式。 在我之前的文章中,已經提到過,NSRunLoop在使用上有一些條件。 我所沒有明確的提出的是,你的需求並不適宜使用NSRunLoop。 關於這點,icecicada的文章中說得很清楚,你所需要使用的是NSThread或NSTimer。 在這裡,我再解釋得清楚一點: 1. 執行緒與Run Loop是不同的兩回事。 所謂的多緒,指的是「同時進行」的工作。在多核心,或是多處理器的環境下, 要達到「同時進行」的目的,可將不同的執行緒,交由不同的核心去處理如下: T1(task 1) T2(task2) | | | | ↓ ↓ 而RunLoop呢,其實是用來實現所謂的「分時多工」,其動作如下: T1 |←────┐ |(task 1) | | | |(task 2) | | | └─────┘ 在過去單核單處理器的情形下,因為多緒的「同時進行」一事,也是用「分時多工」的 方式去達成,所以有時會比較容易搞混。 2. NSRunLoop本質上雖然是一個迴圈,但與while(),for()的意義及使用目的不同。 如前所述,NSRunLoop是用來實現「分時多工」的,所以裡面除了「重複」外, 還會做所謂的Dispatch,也就是「工作分配」。 但while() 及for()這種基礎的迴圈,就只是很單純的「重複」。 3. 回到你的需求,你希望 a.重複做某件事 b.當滿足某條件時,停止a. 你可以很清楚的看到,你的需求a,只有「重複」的要求而已,而不需要「分配工作」。 因此你根本不需要用到NSRunLoop來幫你做事。 至於需求b,則可以用「分時」的方式,或是「多緒」的方式擇一來達成。 也就是在這裡,你可能搞混了,誤以為你的需求 a+b 一定要存取到NSRunLoop。 多緒的方式,上面的虛擬碼應該已經很清楚,我這邊講解一下「分時」的做法。 首先,如icecicada所述,在Cocoa應用程式執行時,其實已經有一個NSRunLoop在跑了。 它看起來可能像是下面這樣: Main Thread |←───────┐ |(do GUI task) | |(get event) | |(dispatch event)| |(blahblah...) | └────────┘ 我們可以看到,在這個Run Loop中,其實已經有許多重複的工作了, 這些重複的工作,負責維護應用程式的各種狀態, 並處理使用者對應用程式所做的各類動作。 而當你想要「重複」某件工作時,在597篇你做的事是: Main Thread |←───────┐ |(do GUI task) | |(get event) | ┌┤(dispatch event)|(blahblah...) | └────────┘ | └→ 1.如果startEvent: 1.1 doLoop:(進入迴圈) 1.1.1 do something 因為在1.1,你進入了一個迴圈,造成Main thread一直停在一個副迴圈中, 所以無法再繼續進行get event, dispatch event,do other things的流程。 在分時的情況下,你真正應該做的事是像下面這樣: Main Thread |←───────┐ |(do GUI task) | |(get event) | |(dispatch event)| |(blahblah...) | |1.1.1 do something (將1.1.1加入Run Loop) └────────┘ 這也是你在上一篇所試著要做的。 但是,雖然你試著要將一個新工作加入Run Loop, 但因為你沒有弄清楚NSTimer與NSRunLoop的角色,所以會寫出一些多餘的程式。 當你在產生一個NSTimer,並將之與某個Selector結合時, 其實就已經幫你做好上面所描述的事情了,所有與NSRunLoop相關的操作, 都已經在NSTimer的實作中幫你做完了,你不需要自己再去做一次。 你要做的只有: 1. 產生一個NSTimer,並指定要做的事情(Selector) 2. 起動(fire)所產生的Timer 在2.的時候,NSTimer就會自動幫你將Selector加入Current Run Loop。 而當你呼叫[NSTimer invalidate]時,NSTimer就會幫你把方才加入的Selector, 移出Current Run Loop. 從上面,你也可以看出,為何icecicada會說: 「如果是一直在執行,或是執行需要花費較長的時間,還是使用Theard會比較好...」 因為你還是在同一個Thread中,而不是不同的Thread。 而使用多緒的方式,執行起來會像下面: Main Thread child |←───────┐ |←───────┐ |(do GUI task) | |(do 1.1.1) | |(get event) | └───┬────┘ |(dispatch event)| | |(blahblah...) | | └───────┬┘ | └────→A←─┘ 這時候要讓child停下來,就得有一個變數A,能夠同時讓Main Thread與child存取。 這樣你才能在Main Thread中改變A的狀態, 而在Child中檢查A的狀態,並決定要不要停下來。 至於更詳細的class用法,還是請你去查一下NSTimer,NSThread的文件, 並參考一下別人的範例。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 219.84.252.229

05/12 20:36, , 1F
感謝你 真的是說明的很清楚 我今天自己有利用新產生一個
05/12 20:36, 1F

05/12 20:37, , 2F
Thread然後加工作到裡面結果可以執行了 不過我覺得我還是
05/12 20:37, 2F

05/12 20:40, , 3F
有多寫了一些步驟 我會再多用清楚一點的 謝謝感激不盡!
05/12 20:40, 3F
文章代碼(AID): #18A2fD42 (MacDev)
討論串 (同標題文章)
文章代碼(AID): #18A2fD42 (MacDev)