为什么发布通知会导致崩溃?

5

我使用以下代码发布通知,但它会崩溃并显示EXC_BAD_ACCESS:

[[NSNotificationCenter defaultCenter]postNotificationName:AUTHENTICATED_NOTIFICATION object:nil];

在我的constants.h文件中:

#import <Foundation/Foundation.h>

extern NSString *const PLAYER_ID;
extern NSString *const RANDOM_NUMBER;

extern NSString *const AUTHENTICATED_NOTIFICATION;
extern NSString *const UNAUTHENTICATED_NOTIFICATION;

@interface RIYConstants : NSObject
{

}

@end

在我的constants.m文件中

#import "RIYConstants.h"

NSString *const PLAYER_ID = @"playerId";
NSString *const RANDOM_NUMBER = @"randomNumber";

NSString *const AUTHENTICATED_NOTIFICATION = @"AUTHENTICATED_NOTIFICATION";
NSString *const UNAUTHENTICATED_NOTIFICATION = @"UNAUTHENTICATED_NOTIFICATION";

@implementation RIYConstants

@end

当游戏中心进行身份验证时,会调用处理程序,导致程序崩溃的方法为:处理程序。
-(void)authenticatedPlayer:(GKLocalPlayer*)localPlayer
{
    [[NSNotificationCenter defaultCenter]postNotificationName:AUTHENTICATED_NOTIFICATION object:nil];
     ......
}

我不知道为什么它会崩溃。通知发布时并非每次都会崩溃(似乎是随机的)。

编辑: 只有一个对象注册接收通知。下面是init方法和调用的选择器。我认为没有任何原因会导致崩溃。_label和_joinGame都是SKLabelNodes。

-(id)init
{ ...
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(addGameCenterOption) name:AUTHENTICATED_NOTIFICATION object:nil];
...
}

-(void)addGameCenterOption
{
    _label.text = @"";
    _joinGame.text = @"Start multiplayer game";
    _signedIn = YES;
}

编辑:我已经更改了应用程序,使得没有对象注册来观察通知,但它仍然会(随机)崩溃。


3
是否有其他已被释放的对象注册接收此通知,但在释放之前未注销? - mah
在应用程序的生命周期内,只有一个对象已注册以观察此事件,并且它永远不会被释放。 - Rahul Iyer
你收到了什么崩溃信息? - KAREEM MAHAMMED
EXC_BAD_ACCESS(code=1,address=0xb14595d5) - Rahul Iyer
你确定它不是在你的通知处理程序中崩溃了吗? - Hot Licks
是的,我确定。它在我发布通知的那一行崩溃了,而且无法重现 - 随机发生。 - Rahul Iyer
3个回答

2

很可能是由于已在发送通知时释放的已注册观察者,但观察者未注销所致。

请确保所有添加观察者的类:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addGameCenterOption) name:AUTHENTICATED_NOTIFICATION object:nil];

在它们被释放之前,确保移除观察者:

[[NSNotificationCenter defaultCenter] removeObserver:self AUTHENTICATED_NOTIFICATION object:nil];

只有一个对象被注册用于监听,而且它从未被释放。 - Rahul Iyer

1
由于您正在修改UI元素,请在addGameCenterOption的开头添加一个assert来确保您处于主线程上。此外,在与元素交互之前,做一些间接的事情,比如记录它们的类以验证在设置任何属性之前它们仍然存在。
如果您设置了异常断点(左侧面板),Xcode应该会显示导致崩溃的确切行。

0

对我来说,这是因为我的选择器的函数签名不正确。我指定了一个没有参数的选择器:#selector(MyClass.myFunc)

但是该方法的定义如下:

class MyClass {
    ...

    @objc func myFunc(completion: (() -> ())?)
        // function body
    }
}

在意识到这个签名不允许用于选择器之后,我更新了我的代码,像这样。

class MyClass {
    ...

    @objc func functionForMySelector() {
        myFunc(completion: nil)
    }

    func myFunc(completion: (() -> ())?)
        // function body
    }
}

然后像这样定义了我的选择器:#selector(MyClass.functionForMySelector)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接