如何在另一个线程上正确打开和关闭 NSStream

2023-12-24

我有一个应用程序在另一个线程上使用 NSStream 连接到服务器。如果用户决定注销,应用程序还会关闭连接。问题是我永远无法在用户断开连接时成功关闭流或线程。下面是我的代码示例,介绍了如何为我的网络创建线程并尝试关闭流:

+ (NSThread*)networkThread
{
    static NSThread *networkThread = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        networkThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkThreadMain:) object:nil];

        [networkThread start];
    });

    return networkThread;
}

+ (void)networkThreadMain:(id)sender
{
    while (YES)
    {
        @autoreleasepool {
            [[NSRunLoop currentRunLoop] run];
        }
    }
}

- (void)scheduleInThread:(id)sender
{
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    [inputStream open];
}

- (void)closeThread
{    
    [inputStream close];
    [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    [inputStream release];
    inputStream = nil;
}

尝试连接输入流时进行的调用:

[self performSelector:@selector(scheduleInThread:) onThread:[[self class] networkThread] withObject:nil waitUntilDone:YES];

任何意见是极大的赞赏。


混合静态变量和实例变量的方式令人困惑。你愿意这样做吗?如果您将其放入 NSOperation 中并使用 NSOperationQueue 运行它,我认为您会获得更清晰的封装。该操作将管理自己的异步线程,因此您不必这样做。另外,如果可以的话,我强烈建议使用 ARC。

一些注意事项:

  1. 确保设置流的委托并处理委托事件。您可能应该在操作内部执行此操作(使操作成为委托)并关闭流并在必要时完成操作。
  2. 除了 NSStreamStatusClosed 之外,流还可能存在其他失败情况,例如 NSStreamStatusNotOpen 等。您可能需要添加额外的处理,这可以通过侦听委托方法来完成。
  3. 您的代码可能无法正常工作,主要是因为您的 while 循环永远运行 runloop。必须具备爆发的条件。 NSOperation 为您提供了一些非常好的标准化方法来执行此操作。
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface AsyncStreamOperation : NSOperation

@end

NS_ASSUME_NONNULL_END
#import "AsyncStreamOperation.h"

@interface AsyncStreamOperation ()

@property (atomic, strong) AsyncStreamOperation *config;

@property (atomic, strong) NSInputStream *stream;

@property (atomic, assign, getter=isExecuting) BOOL executing;
@property (atomic, assign, getter=isFinished) BOOL finished;

@end

@implementation AsyncStreamOperation

@synthesize executing = _executing;
@synthesize finished = _finished;

- (instancetype)initWithStream:(NSInputStream *)stream
{
    self = [super init];
    
    if(self) {
        _stream = stream;
    }
    
    return self;
}

- (BOOL)isAsynchronous
{
    return YES;
}

- (BOOL)isExecuting
{
    @synchronized (self) {
        return _executing;
    }
}

- (void)setExecuting:(BOOL)executing
{
    @synchronized (self) {
        [self willChangeValueForKey:@"isExecuting"];
        _executing = executing;
        [self didChangeValueForKey:@"isExecuting"];
    }
}

- (BOOL)isFinished
{
    @synchronized (self) {
        return _finished;
    }
}

- (void)setFinished:(BOOL)finished
{
    @synchronized (self) {
        [self willChangeValueForKey:@"isFinished"];
        _finished = finished;
        [self didChangeValueForKey:@"isFinished"];
    }
}

- (void)start
{
    // Get runloop
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    
    // Schedule stream
    [self.stream scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
    [self.stream open];
    
    // Loop until finished
    // NOTE: If -cancel is not called, you need to add your own logic to close the stream so this loop ends and the operation completes
    while(self.executing && !self.finished && !self.cancelled && self.stream.streamStatus != NSStreamStatusClosed) {
        @autoreleasepool {
            // Maximum speed once per second or CPU goes through the roof
            [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
        }
    }

    self.executing = NO;
    self.finished = YES;
}

- (void)cancel
{
    [super cancel];
    
    [self.stream close];
    
    self.executing = NO;
    self.finished = YES;
}

@end

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在另一个线程上正确打开和关闭 NSStream 的相关文章

  • 我如何从 iPhone 设备获取电子邮件历史记录..?

    friends 我想从我的 iPhone 访问电子邮件历史记录 并且还希望在收到新邮件时收到通知 如果可能的话 请向我提供源代码片段 Thanks 简而言之 使用任何已记录的 API 都是不可能的
  • 所有针对 iTunes Connect 的构建,导入此构建时出错 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我将构建上传到应用程序商店 之后它在活动中显示错误 任何人都可以帮帮我 SOLVED 转到构建设置 gt 搜索 bitcode gt 转启
  • 由于 2.23 导致 iOS 应用程序被拒绝 - iOS 数据存储指南

    以下是 Apple 关于拒绝的消息 2 23 应用程序必须遵循 iOS 数据存储指南 否则将被拒绝 2 23 详情 在启动和内容下载时 您的应用程序会存储 6 5 MB 这并不意味着 遵守 iOS 数据存储指南 下一步 请验证只有用户使用您
  • 使用 nib 作为带有 nib 类的表节标题

    我想创建一个加载 nib 文件并将其设置为标题 UIView 的节标题 这个 nib 文件还将有一个关联的类 其中插座和操作连接到 因此我想像平常一样使用 nib 加载该类 我在网上搜索并找到了几个类似的答案 但我找不到任何适合我的答案 经
  • Google Cloud Messaging 显示成功消息但未发送 iOS

    所以我在使用 Google Cloud Messaging 时遇到了一个非常奇怪的问题 我遇到的问题是它正在成功注册设备 并且当发送消息时我会收到来自 Google 的成功消息 但设备永远不会收到任何消息 我从 GCM 得到的消息是 res
  • iOS 13 检查 CLLocationManager 的临时授权状态

    根据 WWDC 视频 https developer apple com videos play wwdc2019 705 https developer apple com videos play wwdc2019 705 当你要求 Al
  • 使我的 COM 程序集调用异步

    我刚刚 赢得 了在当前工作中维护用 C 编码的遗留库的特权 这个dll 公开使用 Uniface 构建的大型遗留系统的方法 除了调用 COM 对象之外别无选择 充当此遗留系统与另一个系统的 API 之间的链接 在某些情况下 使用 WinFo
  • UITesting、XCTest 当前 ViewController 类

    简单的问题 我有一个按钮可以执行到下一个视图控制器的操作 我想写 UI XCTest 来告诉我它是否打开了我想要的视图控制器 UI 测试框架无法访问您的应用程序代码 这使得无法对实例进行类断言 你不能够directly告诉屏幕上的控制器的类
  • 在 UITextView 中获取 HTML

    我在中显示htmlUITextView by self textView setValue b Content b forKey contentToHTMLString 编辑内容后UITextView 我想获取包含 html 的内容 所以我
  • 使用自动布局、IB 和字体大小时表头视图高度错误

    我正在尝试为我的 uiTableView 创建一个标题视图 不是节标题 我已经有了 我已经在界面生成器中设置了一个 XIB 所有的连接都已连接好并且运行良好 除了桌子没有给它足够的空间 我的问题是表格顶部与表格标题有一点重叠 我的 XIB
  • 如何使用 Swift 将“完成”按钮添加到 iOS 中的数字键盘?

    它在默认键盘上工作得很好 但我无法让它在数字键盘上工作 有任何想法吗 据我所知 你不能在键盘部分添加 完成 按钮 你应该添加一个inputAccessoryView to the UITextField or UITextView 如果这就
  • 访问 google reader 的 Endpoints API 时出错

    我正在尝试在iPhone APP中实现google reader 到目前为止我已经成功收到了sid and auth 当我尝试使用以下命令调用 Endpoints API 时 问题就出现了GET 这是代码 ASIHTTPRequest re
  • Swift:协议、结构、类

    我开始学习 Swift 语言 但在理解协议 结构和类方面遇到了困难 我来自 Android 方面的编程 所以我相信 Swift 协议基本上是 Java 接口 其中每一个的正确用例是什么 这些类比并不 完全 正确 但这就是我所理解的要点 是的
  • 带有 allowedEditing 的 UIImagePickerController 不允许平移裁剪

    我在这里看到这个问题 UIImagePicker 允许编辑卡在中心 https stackoverflow com questions 12630155 uiimagepicker allowsediting stuck in center
  • Erlang 如何睡觉(晚上?)

    我想在 Erlang 服务器上每隔几个小时运行一次小型清理过程 我知道计时器模块 我在教程中看到一个示例 使用链式计时器 睡眠命令来等待几天后发生的事件 我觉得这很奇怪 我知道 Erlang 进程与其他语言中的进程相比是独一无二的 但是进程
  • 如何在 iOS 上固定证书的公钥

    在提高我们正在开发的 iOS 应用程序的安全性时 我们发现需要对服务器的 SSL 证书 全部或部分 进行 PIN 操作以防止中间人攻击 尽管有多种方法可以做到这一点 但当您搜索此内容时 我只找到了固定整个证书的示例 这种做法会带来一个问题
  • 当 ViewController 从 UIStoryboard 实例化时,isMemberOfClass 返回 no

    我有一个 OCUnit 测试类 PatientTestViewControllerTests 下面是界面 interface PatientTestViewControllerTests SenTestCase property nonat
  • 使用单独的线程在java中读取和写入文件

    我创建了两个线程并修改了 run 函数 以便一个线程读取一行 另一个线程将同一行写入新文件 这种情况会发生直到整个文件被复制为止 我遇到的问题是 即使我使用变量来控制线程一一执行 但线程的执行仍然不均匀 即一个线程执行多次 然后控制权转移
  • 如何将自定义 C 代码放入 SwiftPM 包中?

    我正在尝试将 C 代码打包到 Swift 模块中 我们称之为CModule 一旦我将其放入项目的基本文件夹中 Swift模块 并配置了搜索路径 我可以在 Swift 文件中自动完成工作 并检测错误 警告 问题是 导入时它无法识别该模块 并且
  • 当底层连接是有状态时如何使用 Apache HttpClient?

    我在谷歌上搜索了很多关于如何使用 HttpClient 进行多线程处理的信息 他们中的大多数人建议使用 ThreadSafeClientConnManager 但我的应用程序必须登录某个主机 登录表单页面 以便 HttpClient 获得底

随机推荐

  • 在 ruby​​ on Rails 中包含 httparty 时出现问题

    我一直在尝试在我的 Rails 代码中使用 HTTParty sudo gem install httparty 从命令行我现在可以成功地执行 httparty http twitter com statuses public timeli
  • 如何在 PostgreSQL 中进行仅模式备份和恢复?

    如何在 PostgreSQL 数据库中进行架构级备份并在另一个数据库上恢复 有没有可用的单个命令 例如 我可以在单行中进行 pg dump 和恢复吗 pg dump schema masters oldDB gt masters1 sql
  • 如何正确缓存我的 Symfony2 API?

    我正在 Symfony2 上制作经典的无状态 RESTfull API 用户 应用程序在身份验证 API 上获取身份验证令牌 并将其提供给所有其他 API 进行记录并发布数据 访问其他 API 上的受保护 私有 个人数据 我现在对这个工作流
  • 没有 $unwind 的 $group 内部数组值

    我想按指定字段的相同值对数组中的对象进行分组并生成计数 我有以下 mongodb 文档 不存在不相关字段 arrayField fieldA value1 otherFields fieldA value2 otherFields fiel
  • 如何创建收益递减的公式?

    我想这是一个数学问题 而不是一个编程问题 但是创建收益递减公式的好方法是什么 以下是一些关于我希望曲线看起来如何的示例点 f 1 1 f 1 5 98 f 2 95 f 2 5 9 f 3 8 f 4 7 f 5 6 f 10 5 f 20
  • 对相关包进行排序

    我有一个 Pig 脚本 它生成了一个关系 A x chararray B y chararray z int 我想根据 B y 对 A 进行排序 但是以下代码给了我错误 语法错误 z 处或附近出现意外符号 output foreach A
  • 用户代理标头 - mysql 存储的缩写

    根据这个帖子 特别是这篇文章 https stackoverflow com a 6595973 1125465 https stackoverflow com a 6595973 1125465 微软一如既往地炫耀 用户代理的大小可能非常
  • 在范围内找不到类型 GIDSignInDelegate

    如下所示 我收到这些错误 我已经安装了 Firebase 和 GoogleSignIn 我做错了什么 正如克里斯在评论中指出的那样 请遵循迁移指南 https developers google com identity sign in i
  • DotNetNuke——所有登录都在任何地方被跟踪吗?

    我知道您可以在 用户 表的 LastModifiedOnDate 列中找到用户上次登录的时间 但我有兴趣查找用户登录时时间戳的完整历史记录 这可能吗 如果是这样 该信息存储在哪个表中 Thanks 日志查看器中存储了一个事件 即EventL
  • 将不同的结构复制到字节数组

    我正在将旧的 Visual BASIC 程序转换为 C 该程序通过串行或以太网线路向某些工业机械发送消息 为此 它创建消息的字节数组 问题是有MANY 50 种不同的消息格式 每种格式在 VB6 中定义为用户定义类型 例如 Public T
  • 如何在python中通过对象的属性从对象列表中选择对象

    如果这个问题已经被问过 我深表歉意 但我认为我不知道通过谷歌搜索合适的解决方案的正确术语 我想通过对象的属性值从对象列表中选择一个对象 例如 class Example def init self self pList def addPer
  • 将 UWP 应用程序最小化到系统托盘

    有没有办法将 Windows 10 UWP 应用程序最小化到系统托盘 我试过用谷歌搜索这个问题 但我所能看到的只是关于 wpf 和 windows 窗体 Thanks 这是不可能的 但是 根据您在评论中的描述 不需要 Cortana 将启动
  • 正则表达式查找单引号之间的空格并替换为下划线

    我有一个已导出的数据库表 我需要用空格替换图像文件名 并想使用记事本 和正则表达式来执行此操作 我有 data green tea powder jpg data prod img lumina herbal shampoo JPG dat
  • 如何在 Flask 微框架中使用 Neo4j-embedded for Python(线程)?

    我正在遵循 Flask 教程 Flaskr 以便尝试使用 Python 嵌入的 Neo4j 这是在 virtualenv 中 这是我的 主要 应用程序代码 import os import jpype from neo4j import G
  • 分割逗号分隔的字符串 --> FUNCTION db.CHARINDEX 不存在

    我需要将逗号分隔的字符串拆分为第二列 我有下表 CL1 POS POS2 LENGHT ALLELE 1 3015108 3015109 5 A 2 3015110 3015200 10 B 3 3015200 3015300 15 C 4
  • 为 PHPUnit 配置文件名

    我是 PHPUnit 的新用户 我正在将现有的测试 断言 转换为 PHPUnit 框架 以提供更好的测试环境和代码覆盖率 但是 我需要知道如何尝试让 PHPUnit 使用我们的测试代码结构 我们的项目目录类似于以下内容 应用1 CREDIT
  • 如何在处理开发环境(PDE)中进行调试,还有支持智能感知的插件吗

    我是处理开发环境的新手 我做了功课 我发现的只是将处理库导入Java IDE eclipse 并使用调试 我想知道是否有一个PDE插件可以帮助进行智能感知和调试 就像小草图偏微分方程非常方便 调试 自推出以来处理3 调试现在是Process
  • Laravel in_array 验证规则

    我定义了一个数组 this gt allslots array 10 00 00 10 10 00 10 20 00 10 30 00 10 40 00 10 50 00 11 00 00 11 10 00 11 20 00 11 30 0
  • C 中基本数据类型的大小

    我有一个从某个网站复制的示例程序 int main void int answer short x 1 long y 2 float u 3 0 double v 4 4 long double w 5 54 char c p typede
  • 如何在另一个线程上正确打开和关闭 NSStream

    我有一个应用程序在另一个线程上使用 NSStream 连接到服务器 如果用户决定注销 应用程序还会关闭连接 问题是我永远无法在用户断开连接时成功关闭流或线程 下面是我的代码示例 介绍了如何为我的网络创建线程并尝试关闭流 NSThread n