15

我有一个 NSRunLoop 对象,我将计时器和流附加到该对象。它工作得很好。停止它是另一个故事。

我使用[runLoop run].

如果我尝试使用 停止循环CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]),则循环不会停止。如果我改为使用开始循环CRunLoopRun(),它会起作用。我还确保调用是在正确的线程(运行我的自定义运行循环的线程)上进行的。我已经用pthread_self().

CRunLoopStop()我找到了一个邮件列表存档,其中一位开发人员说“如果您使用 run 方法启动循环,请不要打扰使用NSRunLoop”。我可以理解为什么会这样——你通常将初始化器和终结器从同一组函数中配对。

你如何阻止一个NSRunLoop没有“诉诸CF”的人?我没有stopNSRunLoop. 文档说您可以通过三种方式停止运行循环:

  1. 配置运行循环以使用超时值运行
  2. 告诉运行循环停止使用CFRunLoopStop()
  3. 移除所有输入源,但这是停止运行循环的一种不可靠的方法,因为你永远无法知道是什么东西卡在了你背后的运行循环中

好吧,我已经尝试了 2。它有一种“丑陋”的感觉,因为你必须深入研究 CF。3. 不可能——我不喜欢非确定性代码。

这给我们留下了 1。如果我正确理解了这些文档,您就不能将超时“添加”到已经存在的运行循环中。您只能在超时的情况下运行新的运行循环。如果我运行一个新的运行循环,它不会解决我的问题,因为它只会创建一个嵌套的运行循环。我还是会回到旧的,我想停下来……对吧?我可能误解了这一点。另外,我不想使用超时值运行循环。如果我这样做了,我将不得不在消耗 CPU 周期(低超时值)和响应能力(高超时值)之间进行权衡。

这是我现在的设置(伪代码):

通讯器.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 层是否可能是危险的(关于内存损坏、不一致、内存泄漏)?是否有更好的模式来实现我想要实现的目标?

4

1 回答 1

9

你做得很好。当您无法通过 Foundation 实现目标时,使用 CoreFoundation 没有问题。由于 CoreFoundation 是 C,因此更容易搞乱内存管理,但使用CFRunLoop而不是没有内在的危险NSRunLoop有时它甚至可能更安全CFRunLoopAPI 是线程安全的,NSRunLoop但不是)。

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

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

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

于 2011-12-21T14:03:46.710 回答