当前位置:  开发笔记 > IOS > 正文

主线程的NSRunLoop在辅助线程中被引用

如何解决《主线程的NSRunLoop在辅助线程中被引用》经验,为你挑选了1个好方法。

我最近刚试着用一个样本应用试图让我的脑袋完全缠绕NSRunLoop.我编写的示例创建了一个简单的辅助线程via NSOperation.辅助线程执行一些任务,例如处理NSTimer和一些基本的流媒体NSStream.这两个输入源都需要正确配置NSRunLoop才能执行.

我的问题是这个.最初我在辅助线程中有一些看起来像这样的代码:

NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:connectTimeout
                                                     target:self
                                                   selector:@selector(connectionConnectedCheck:)
                                                   userInfo:nil 
                                                    repeats:NO];

[myRunLoop addTimer:self.connectTimer forMode:NSDefaultRunLoopMode]; // added source here
[myRunLoop run];

[NSStream getStreamsToHostNamed:relayHost port:relayPort inputStream:&inputStream outputStream:&outputStream];
if ((inputStream != nil) && (outputStream != nil))
{
    sendState = kSKPSMTPConnecting;
    isSecure = NO;

    [inputStream retain];
    [outputStream retain];

    [inputStream setDelegate:self];
    [outputStream setDelegate:self];

    [inputStream scheduleInRunLoop: myRunLoop //[NSRunLoop currentRunLoop]  
                                    forMode:NSRunLoopCommonModes];
    [outputStream scheduleInRunLoop: myRunLoop //[NSRunLoop currentRunLoop] 
                                    forMode:NSRunLoopCommonModes];

    [inputStream open];
    [outputStream open];

    self.inputString = [NSMutableString string];



    return YES;
}

现在,使用上面的代码,事件永远不会处理.不上currentRunLoop.之后我做了一些可怕的事情,因为这只是一个教育练习,并将其修改为运行NSRunLoop mainRunLoop.像魔术一样工作.但是,我几乎可以肯定,根据我的主线程,在辅助线程中运行循环是在10个不同级别的错误.

所以我的问题分为两部分,我希望没问题.

    为了让次级线程运行并通过运行循环响应事件,我应用的小"hack"可能出现什么问题?

    配置辅助线程以侦听所有基于事件/定时器的源的正确方法是什么,所以我不必执行第1步.

感谢所有人的洞察力.



1> BJ Homer..:

以相反的顺序回答您的问题:

2.你有两个问题.文档-[NSRunLoop run]说:

如果没有输入源或定时器附加到运行循环,则此方法立即退出; 否则,它NSDefaultRunLoopMode通过反复调用来运行接收器 runMode:beforeDate:.换句话说,这种方法有效地开始了一个无限循环,它处理来自运行循环的输入源和定时器的数据.

因此,使用线程自己的运行循环,可能没有为运行循环定义输入源,因此它会立即返回.如果存在,则运行循环无限循环,并且在该点之后的其余代码永远不会被执行.

为了使事情正常工作,您的运行循环首先需要一些输入源,然后需要定期运行以检查事件.请注意,您不想使用[NSRunLoop run],因为您永远无法控制.相反,我建议在return YES不断运行运行循环之前设置一个循环,直到线程被取消,或者直到你完成流数据.这将允许运行循环在数据到达时处理数据.像这样的东西:

while (!done) {
    [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}

[NSRunLoop runUntilDate:] 将事件处理到指定的日期,然后将控制权返回给您的程序,以便您可以执行任何操作.

1.它的工作,因为你的主线程的运行循环周期性地运行,因此事件得到处理.但是,如果您的主线程被阻止,您的数据将停止到达.如果主线程正在等待第二个线程的数据,这可能会特别糟糕.此外,NSRunLoop不是线程安全的:

警告:NSRunLoop类通常不被认为是线程安全的,并且只应在当前线程的上下文中调用其方法.您永远不应该尝试调用在不同线程中运行的NSRunLoop对象的方法,因为这样做可能会导致意外结果.(来自NSRunLoop文档.)

Apple的线程编程指南有一个名为Run Loop Management的部分,它在一定程度上解释了所有这些.这不是我读过的最清晰的文档,但是如果你正在使用run loop,那么这是一个很好的起点.

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有