我真的不知道这是线程的问题,但我不知道还有什么可能导致我的问题。我有一个iOS应用它有一个NSStreamDelegate调用
- (void) stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
委派被赋予一个AppDelegate的句柄,并且在StreamDelegate的其他部分,AppDelegate存在。然而,在stream:handleEvent:中,当我试图将结果传递回AppDelegate进行额外处理时,我得到了EXC_BAD_ACCESS错误。
我认为这可能是线程问题的唯一原因是stream:handleEvent: states:
只有当流被安排在运行循环中时,委托才会收到此消息。消息在流对象的线程上发送。委托应该检查streamEvent以确定它应该采取的适当操作。
是否"流对象的线程"指的是我的StreamDelegate?或者这是对传递给方法的流的引用?我假设是后者,但我想确保我没有搞错。
如果它是一个不同的线程比我的AppDelegate坐,然后是什么导致我的问题?如果是,我该如何处理?
编辑: per @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: selector完成它的工作,然后修改视图中的属性以表明它是脏的。这个属性被触动了。当我打断它的时候,我看到它发生了。但是viewWillAppear:永远不会被调用。
这真是太令人沮丧了。这似乎是一件很简单的事情,但这是多么混乱啊。
是否"流对象的线程"指的是我的StreamDelegate?或者是对流的引用被传递到方法中?我假设我想确认一下我没有弄错。
每个线程只能有一个运行循环。该委托将在拥有流被调度的运行循环的任何线程上被调用。
如果它和AppDelegate所在的线程不同,则是是什么导致了我的问题?如果是,我该如何处理?
可能是;如果你的AppDelegate不是线程安全的,并且流被安排在一个非主线程上,那么很可能出现问题。
没有更多的信息,不可能说更多。由于应用程序正在崩溃,你应该发布回溯,至少。
解决了吗?我正在做一些非常类似的事情,并有它的工作,虽然我遇到了一个问题,随机不接收应该出现在流上的所有字符。
如果有帮助的话,我可以张贴在我的情况下工作的代码。
实际上,我的代码是启动一个后台线程,然后委托使用它来监视流。
-(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];
}
流委托OpenSession指定以以下方式在当前线程上运行。
[[currentSession inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[currenSession outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
当我想让appDelegate知道一些事情时,我通常使用一个NSNotification,它已经为事件注册了。
[[NSNotificationCenter defaultCenter] postNotificationName:@"DataReceived" object:_receivedData];
希望对你有帮助。
对