【问题标题】:Objective-C issues with threading and streams?线程和流的 Objective-C 问题?
【发布时间】:2011-12-07 06:20:17
【问题描述】:

我不确定这是线程问题,但我不知道还有什么可能导致我的问题。我有一个调用 NSStreamDelegate 的 iOS 应用

- (void) stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode

委托被赋予了 AppDelegate 的句柄,并且在 StreamDelegate 的每个其他部分中,AppDelegate 都存在。但是,在 stream:handleEvent: 中,当我尝试将结果传递回 AppDelegate 进行额外处理时,我收到了 EXC_BAD_ACCESS 错误。

我认为这可能是线程问题的唯一原因是关于 stream:handleEvent: states: 的文档:

只有当 theStream 被安排在一个运行循环上时,代理才会收到这个消息。消息在流对象的线程上发送。委托应检查 streamEvent 以确定应采取的适当操作。

“流对象的线程”是指我的 StreamDelegate 吗?或者这是对传递给方法的流的引用?我假设是后者,但想确保我没有弄错。

如果它 与我的 AppDelegate 所在的线程不同,那么这就是导致我的问题的原因吗?如果是这样,那我该如何处理呢?

编辑:根据@bbum,我正在更新以表明我做了什么。

在闲逛之后,我尝试了一些我考虑过的东西,然后被解雇了。本质上,我创建了一个从 stream:handleEvent: 实例化和调用的虚拟类。我调用的方法是:

[man performSelectorOnMainThread:@selector(saveEvent:) withObject:jsonDict waitUntilDone:YES];

在 saveEvent: 内部,我回调 AppDelegate 并且(几乎!)从那时起一切正常。

我目前遇到问题,调试器抱怨尝试写入不存在的文件。我还不知道为什么会这样。文件名看起来有点像在“iPhone Simulator/5.0/Applications/”下为应用程序创建的散列目录,但我还没有弄清楚错误发生在哪里。

真正搞砸的部分是我根本无法获得任何崩溃的堆栈跟踪。我尝试使用 LLVM 3.0 和 LLVM GCC 4.2 以及相应的调试器,但没有。我正在使用 Xcode 4.2。我的 4.1 没有这个问题。

感谢您的智慧之言,@bbum。非常感激。一旦我完全解决了这个问题,我会发布另一个更新。

编辑(2011-10-18): [更新:没关系;我是个白痴。我正在将流读入字节数组,但没有声明明确的大小。我遇到了某种缓冲区溢出。现在一切正常。]

由于上述错误,我这几天一直在撞墙,然后重写代码。我又快要让一切正常工作了,但线程似乎仍然在咬我。

我收到以下错误:

警告:无法恢复之前选择的帧。

我正在做的是接收 NSInputStream 上的数据并将其写出,然后尝试刷新视图以指示更新。在调用之后的某个时间点,我应该会看到对 viewWillAppear:(BOOL)animated 的调用,但上面的警告首先出现并且应用程序被锁定。

我已经在上面进行了广泛的谷歌搜索,通常当存在某种无限循环、堆栈溢出或正在敲击内存的东西时,就会出现错误。我看不到发生这种类型的任何事情。我仍然认为我遇到了一个问题,我的线程已经交叉,并且堆栈变得混乱。我就是不知道为什么。

上面调用的 saveEvent: 选择器完成它的工作,然后修改视图中的一个属性以指示它是脏的。这个属性被触动了。当我休息时,我看到它发生了。但是 viewWillAppear: 永远不会被调用。

这真是令人沮丧。看似很简单的事情,结果却是一团糟。

【问题讨论】:

    标签: objective-c ios multithreading stream


    【解决方案1】:

    “流对象的线程”是指我的 StreamDelegate 吗?或者是 对流的引用被传递到方法中?我假设 后者,但想确保我没有弄错。

    每个线程只能有一个运行循环。委托将在任何线程拥有的 runloop 上调用,该流被调度。

    如果它与我的 AppDelegate 所在的线程不同,那么是 那是什么导致我的问题?如果是这样,那我该如何处理呢?

    可能是;如果您的 AppDelegate 不是线程安全的并且流被安排在非主线程上,那么很可能是问题所在。

    没有更多信息,就不可能说得更多。由于应用程序正在崩溃,您至少应该发布回溯。

    【讨论】:

    • @bburn - 感谢您的信息。不幸的是,我没有得到回溯。我在 Xcode 4.2 中运行,发生崩溃时我没有进行堆栈爬网。不太清楚为什么。我试图调用 performSelectorOnMainThread:...,但我什至自己崩溃了。这很奇怪。
    • 我正在调用 Delegate 内部的 runloop:` _inStream.delegate = self; [_inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [_inStream 打开]; `
    • 如何使 AppDelegate 线程安全?我试图将 StreamDelegate 的实例化放入后台线程,但这没有用。 Obj-C 中的线程有时对我来说有点不直观。
    • 任何语言的线程都是不直观的,除非该语言被设计为线程安全的(此时它通常是内存对抗的)。编辑您的问题以显示您尝试过的内容。
    【解决方案2】:

    你解决了吗?我正在做一些非常相似的事情,尽管我遇到了随机没有接收到应该出现在流中的所有字符的问题,但它仍然可以正常工作。

    如果有帮助,我可以发布适用于我的情况的代码。

    实际上我的代码是启动一个后台线程,然后委托使用该线程来监视流。

    -(void)backgroundThreadFunction:(NSObject*)obj
    {
        [self setBackgroundThread:[NSThread currentThread]];
        [streamDelegate OpenSession:accessoryInfo];
    
        while(_continueRunning) {
            NSAutoReleasePool *_pool = [[NSAutoReleasePool alloc] init];
            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];
            [_pool release];
        }
    
        [self setBackgroundThread:nil];
    }
    

    并且Stream委托OpenSession指定以如下方式在当前线程上运行。

    [[currentSession inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [[currenSession outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    

    当我希望 appDelegate 知道某些事情时,我通常使用已为事件注册的 NSNotification。

    [[NSNotificationCenter defaultCenter] postNotificationName:@"DataReceived" object:_receivedData];
    

    希望对您有所帮助。

    问候

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 1970-01-01
      • 2022-01-08
      • 2011-09-30
      相关资源
      最近更新 更多