作者atst (电脑无法阻止人类做蠢事)
看板MacDev
标题Re: [问题] 请问Cocoa程式要如何一直做同件事情?
时间Mon May 12 19:30:20 2008
※ 引述《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
1F:推 Dannier:感谢你 真的是说明的很清楚 我今天自己有利用新产生一个 05/12 20:36
2F:→ Dannier:Thread然後加工作到里面结果可以执行了 不过我觉得我还是 05/12 20:37
3F:→ Dannier:有多写了一些步骤 我会再多用清楚一点的 谢谢感激不尽! 05/12 20:40