2011-12-21 26 views
14

我有一个NSRunLoop对象,我附加了定时器和流。它效果很好。停止它是另一回事。CFRunLoopRun()与[NSRunLoop运行]

我使用[runLoop run]运行循环。

如果我尝试使用CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop])来停止循环,则循环不会停止。如果我使用CRunLoopRun()来启动循环,它会起作用。我也确定调用是在正确的线程(运行我的自定义运行循环的线程)上进行的。我已用pthread_self()进行调试。

我发现一个邮件列表存档,开发人员说:“如果您使用NSRunLoop的运行方法启动循环,请不要打扰使用CRunLoopStop()”。我可以理解为什么它是这样的 - 你通常将来自同一组函数的初始化器和终结器配对。

如何在没有“诉诸CF”的情况下停止NSRunLoop?我没有在NSRunLoop上看到stop方法。该文档说,你可以通过三种方式停止运行循环:

  1. 配置运行循环与超时值运行
  2. 告诉运行循环停止使用CFRunLoopStop()
  3. 删除所有输入源,但这是一种不可靠的方式来停止运行循环,因为你永远不知道什么卡什么成背着你

好运行循环,我已经尝试过2和有一个“丑”的感觉,因为你必须深入研究CF. 3.是不可能的 - 我不喜欢非确定性代码。

这给我们留下了1.如果我正确理解了文档,您不能将“超时”添加到已存在的运行循环中。您只能在超时运行新的运行循环。如果我运行一个新的运行循环,它不会解决我的问题,因为它只会创建一个嵌套的运行循环。我仍然会弹回旧的,我也想阻止......对吧?我可能误解了这一个。另外,我不想用超时值运行循环。如果我这样做,我必须在燃烧CPU周期(低超时值)和响应性(高超时值)之间进行权衡。

这是建立我现在(伪代码-ISH):

Communicator.h

@interface Communicator : NSObject { 
    NSThread* commThread; 
} 

-(void) start; 
-(void) stop; 
@end 

Communicator.m

@interface Communicator (private) 
-(void) threadLoop:(id) argument; 
-(void) stopThread; 
@end 

@implementation Communicator 
-(void) start { 
    thread = [[NSThread alloc] initWithTarget:self 
            selector:@selector(threadLoop:) 
             object:nil]; 
    [thread start]; 
} 

-(void) stop { 
    [self performSelector:@selector(stopThread) 
       onThread:thread 
       withObject:self 
      waitUntilDone:NO]; 
    // Code ommitted for waiting for the thread to exit... 
    [thread release]; 
    thread = nil; 
} 
@end 

@implementation Communicator (private) 
-(void) stopThread { 
    CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]); 
} 

-(void) threadLoop:(id) argument { 
    // Code ommitted for setting up auto release pool 

    NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 

    // Code omitted for adding input sources to the run loop 

    CFRunLoopRun(); 
    // [runLoop run]; <- not stoppable with 

    // Code omitted for draining auto release pools 

    // Code omitted for signalling that the thread has exited 
} 
@endif 

我是什么去做? CF常见/好的模式?我不太了解基金会。干扰CF层可能是危险的(关于内存破坏,不一致性,内存泄漏)?有没有更好的模式来实现我想要实现的目标?

回答

7

你做得很好。如果您无法实现基金会的目标,那么使用CoreFoundation并没有问题。由于CoreFoundation为C,因此更容易搞乱内存管理,但在使用CFRunLoop而不是NSRunLoopsometimes it may even be saferCFRunLoop API是线程安全的,而NSRunLoop不是)时没有内在危险。

如果你想停止你的NSRunLoop,你可以使用runMode:beforeDate:来运行它。 runMode:beforeDate:在处理输入源后立即返回,因此您无需等到达到超时日期。

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
NSDate *date = [NSDate distantFuture]; 
while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]); 

然后,停止运行循环,你只需要设置runLoopIsStoppedYES

+0

啊,聪明!我没有看到'runMode'只运行一次。通过反复启动运行循环会产生显着的性能损失吗? – 2011-12-21 15:30:41

+0

不,不存在:' - [NSRunLoop运行]'和' - [NSRunLoop runUntilDate:]'是如何工作的。 – 2011-12-21 16:13:41

+1

如果您只将runLoopIsStopped设置为YES,线程将不会停止。 您需要将其设置为YES并对该runloop的线程执行操作,否则[runLoop runMode:NSDefaultRunLoopMode beforeDate:date]不会退出。 这花了我很长时间才弄清楚。 – Pada 2012-06-27 10:57:25