ThoMoNetworking库报错EXC_BAD_INSTRUCTION问题求助
removeFromRunLoop触发EXC_BAD_INSTRUCTION的问题 我之前处理NSStream相关的IPC项目时也碰到过一模一样的错误,虽然你已经确认了inStream和[NSRunLoop currentRunLoop]都不为空,但这种异常通常不是对象为空导致的,而是流的状态或线程匹配出了问题。下面是几个靠谱的排查方向和修复方案:
1. 避免重复调用移除方法
如果removeFromRunLoop:被调用了两次及以上,第二次调用时流已经不在当前runloop的指定mode里了,就会触发这个异常。你可以在调用前先做个简单的检查,确保流确实还关联在当前runloop上:
// 先判断流的状态是否正常,再检查是否在目标runloop mode中 if (inStream.streamStatus != NSStreamStatusClosed && inStream.streamStatus != NSStreamStatusError && [[inStream propertyForKey:NSStreamCurrentRunLoopMode] isEqualToString:NSDefaultRunLoopMode]) { [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; }
2. 严格保证线程一致性
NSRunLoop currentRunLoop是和当前线程绑定的!如果你的close方法是在后台线程调用的,但当初把inStream添加到runloop的操作是在主线程(或者另一个不同的线程)执行的,那在错误的线程上调用removeFromRunLoop:肯定会炸。
解决这个问题的核心是:添加流到runloop和从runloop移除流的操作,必须在同一个线程执行。比如如果之前是在主线程调度的流,那close方法里要切换到主线程执行移除逻辑:
dispatch_async(dispatch_get_main_queue(), ^{ if (inStream) { [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inStream close]; inStream = nil; // 最后一定要置空,防止后续误操作 } });
3. 调整流操作的顺序
有时候先关闭流再从runloop移除会更稳妥,因为流关闭后内部状态会被重置,减少异常触发的概率。另外一定要记得最后把inStream置空,避免野指针问题:
if (inStream) { [inStream close]; // 先关闭流 [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; // 再移除 inStream = nil; }
4. 排查ThoMoNetworking库的内部逻辑
如果以上方案都没用,那可能是库内部对stream的管理有冲突。比如库可能在你不知情的后台线程已经处理了流的关闭/移除操作,导致你在当前线程再次调用时出错。你可以翻一下库的源码,看看TCPConnection类的其他方法(比如回调、错误处理)里有没有对inStream的操作,是不是和你的close逻辑有冲突。
内容的提问来源于stack exchange,提问作者ljRama

