背景
所有我的OpenTok方法都在一个ViewController
中,它被推入视图,就像典型的Master / detail VC关系一样。 detailVC根据您的选择将您连接到不同的房间。当我按下后退按钮弹出视图时,我发生了崩溃(可能是7次中的1次):
[OTMessenger setRumorPingForeground] message sent to deallocated instance xxxxx
或
[OTSession setSessionConnectionStatus:]: message sent to deallocated instance 0x1e1ee440
我在viewDidDisappear中放置了取消发布/断开连接方法:
-(void)viewDidDisappear:(BOOL)animated{
//dispatch_async(self.opentokQueue, ^{
[self.session removeObserver:self forKeyPath:@"connectionCount"];
if(self.subscriber){
[self.subscriber close];
self.subscriber = nil;
}
if (self.publisher) {
[self doUnpublish];
}
if (self.session) {
[self.session disconnect];
self.session = nil;
}
//});
[self doCloseRoomId:self.room.roomId position:self.room.position];
}
这是一个跟踪:
这是Github上的DetailViewController:link here
如何重现:
从MasterVC中进行选择,将您带入DetailVC,立即尝试连接到会话并发布
通常在会话有机会发布流之前快速回到之前的MasterVC
尝试几次,最终会崩溃。
如果我放慢速度并允许发布者有机会进行连接和发布,则不太可能导致崩溃。
预期结果:
它应该断开会话/取消发布并开始一个新的会话,因为我在Master / DetailVC之间往返。
其他
您的设备和操作系统版本是什么? iOS 6
您使用什么类型的连接? 无线网络
Zombies已启用? 是
ARC已启用? 是
代表设置为nil? 是的,据我所知
任何帮助解决这次崩溃的人都将不胜感激。也许我错过了一些我根本无法看到的基本知识。
似乎发生的事情是OpenTok库中的OTSession对象继续向该库中的对象发送消息,这些对象已经被切换视图解除分配。该库有一个[会话断开]方法,如果你给它足够的时间,它可以正常工作,但它需要接近2-3秒,这是很长一段时间在视图之间暂停一个应用程序。
这可能是一个愚蠢的问题,但是: 反正有没有停止某个VC发起的所有进程?
答案 0 :(得分:4)
如果您可以确定视图将被弹出,而不是被推送或隐藏,则从viewWillDisappear()
关闭会话是有效的。一些答案建议将此代码放在dealloc()
中。关于这些建议,Apple says,
您应该尝试使用dealloc 避免管理有限资源的生命周期。
因此,您可以通过以下方式确定您的视图是否会被弹出。从堆栈中弹出视图时会调用viewWillDisappear()
,否则会将其推送到其他位置。这是确定哪个,然后取消发布/断开(如果它真正弹出)的最简单方法。您可以使用isMovingFromParentViewController
对此进行测试。此外,您可以在此处删除特定的观察者。
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]
// This is true if the view controller is popped
if ([self isMovingFromParentViewController])
{
NSLog(@"View controller was popped");
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self.session];
...
//dispatch_async(self.opentokQueue, ^{
if(self.subscriber){
[self.subscriber close];
self.subscriber = nil;
}
if (self.publisher) {
[self doUnpublish];
}
if (self.session) {
[self.session disconnect];
self.session = nil;
}
//});
[self doCloseRoomId:self.room.roomId position:self.room.position];
}
else
{
NSLog(@"New view controller was pushed");
}
}
答案 1 :(得分:3)
在OpenTok
和NSNotificationCenter
类中,OTSession
似乎有使用OTMessenger
的错误。您可以看到调用堆栈中的这些类与NSNotificationCenter
调用分开:
您可以在dealloc(希望OTSession
使用OpenTok
)时手动取消订阅defaultCenter
对象:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self.session];
}
您需要检查此代码(dealloc
)是否真正执行。如果不是 - 您需要解决UIViewController
解除分配的问题。许多其他答案包含如何帮助UIViewController
解除分配的提示。
答案 2 :(得分:2)
-(void)viewDidDisappear:(BOOL)animated
,而不仅仅是从视图堆栈中弹出它时。
因此,如果您在其上推送视图,则会调用viewWillDisappear
并删除您的对象。
如果您从viewDidLoad:
而不是viewDidAppear:
加载这些相同的对象,则会出现此问题。
也许您应该将您的取消发布/断开代码放在-(void)dealloc
。
答案 3 :(得分:2)
这就是Apple suggests:
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
但这只是删除观察者的最后手段,通常仍然是一个好习惯,总是添加它以确保所有内容都清除dealloc以防止崩溃。
remove the observer as soon as the object is no longer ready (or required) to receive notifications仍然是一个好主意。
答案 4 :(得分:1)
我大部分时间都将这样的代码放在viewWillDisappear中,但我想这并不重要。
我认为问题是您的会话代理未设置为nil。只需在viewDidDisappear中添加以下内容:
self.session.delegate=nil;
答案 5 :(得分:1)
你必须调用[super viewDidDisappear:animate];在开始。可能会解决您的问题。 并以dealloc方法更好地清理会话和订阅者:
- (void) dealloc {
[self.session removeObserver:self forKeyPath:@"connectionCount"];
if(self.subscriber){
[self.subscriber close];
self.subscriber = nil;
}
if (self.publisher) {
[self doUnpublish];
}
if (self.session) {
[self.session disconnect];
self.session = nil;
}
[self doCloseRoomId:self.room.roomId position:self.room.position];
//[super dealloc]; //for non-ARC
}
答案 6 :(得分:1)
根据您发布的堆栈跟踪,通知中心会联系到仍处于活动状态的OTSession实例。之后,这个实例会在解除分配的对象上引发崩溃调用方法。 再加上两个不同的解除分配的实例消息,我们知道在某些对象死亡后会发生异步事件,触发您遇到的随机崩溃。
正如ggfela建议的那样,你应该确保你已经连接到OpenTok框架的代表。我强烈建议你在dealloc方法中这样做,因为我们要确保在那之后,没有人对你的对象有任何悬空引用:
- (oneway void)dealloc
{
self.session.delegate = nil;
self.publisher.delegate = nil;
self.subscriber.delegate = nil;
}
代码中另一个奇怪的事情是,sessionDidConnect:
的处理程序每次调用时都会创建一个新的dispatch_queue,以便调用doPublish:。这意味着你有共享SROpenTokVideoHandler实例的并发线程,这使它容易出现竞争条件。