Re: [問題] 請問Cocoa程式要如何一直做同件事情?
※ 引述《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
05/12 20:37, 2F
→
05/12 20:40, , 3F
05/12 20:40, 3F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 6 之 7 篇):