CFRunLoopRun()vs [NSRunLoop运行]

Jör*_*son 15 macos core-foundation foundation cfrunloop nsrunloop

我有一个NSRunLoop对象,我附加了定时器和流.它很棒.停止它是另一个故事.

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

如果我尝试停止循环使用CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]),循环将不会停止.如果我使用CRunLoopRun()相反的方式启动循环,它可以工作.我还确保调用是在正确的线程(运行我的自定义运行循环的线程)上进行的.我调试了这个pthread_self().

我找到了一个邮件列表存档,开发人员说" CRunLoopStop()如果使用run方法启动循环,就不要使用NSRunLoop".我可以理解为什么它是这样的 - 你通常将初始化器和终结器配对来自同一组函数.

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

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

好吧,我已经尝试过2.并且有一种"丑陋"的感觉,因为你必须深入研究CF. 3.不可能 - 我不喜欢非确定性代码.

这给我们留下了1.如果我理解正确的文档,你不能"添加"超时已经存在的运行循环.您只能在超时时运行新的运行循环.如果我运行一个新的运行循环,它将无法解决我的问题,因为它只会创建一个嵌套的运行循环.我仍然会回到原来的那个,同样我想停止......对吧?我可能误解了这个.另外,我不想使用超时值运行循环.如果我这样做,我将不得不在刻录CPU周期(低超时值)和响应性(高超时值)之间进行权衡.

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

Communicator.h

@interface Communicator : NSObject {
    NSThread* commThread;
}

-(void) start;
-(void) stop;
@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*idt 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] );
Run Code Online (Sandbox Code Playgroud)

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