EXC_BAD_ACCESS when setting a CLBeacon to nil

2019-07-28 04:15发布

The following will perform a crash when setting CLBeacon to nil.

CLBeacon *beacon = [[CLBeacon alloc] init];
beacon = nil; // crash

Is it not possible to deallocate an initialized CLBeacon?


This can be reproduced by simply adding the code above to a fresh project inside the App Delegate's didFinishLaunchingWithOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    CLBeacon *beacon = [[CLBeacon alloc] init];
    beacon = nil; // crash
    return YES;
}

2条回答
聊天终结者
2楼-- · 2019-07-28 05:06

The apple documentation for CLBeacon states:

You do not create instances of this class directly. The location manager object reports encountered beacons to its associated delegate object.

The reason it crashes is an implementation detail that doesn't really matter, but it is due to the fact that CLBeacons are not properly initialized when you just call init. When it deallocates, CLBeacon dereferences it's _internal ivar and crashes if it is NULL.

You can see this by looking at the value of the CLBeacon->_internal ivar in the debugger. If you create the beacon using init then the ivar is NULL, but if you create it with [[CLBeacon alloc] initWithCoder:nil] it will have a value and it doesn't crash when you set the beacon to nil.

查看更多
forever°为你锁心
3楼-- · 2019-07-28 05:22

Ran into this problem while using a mocked subclass. My tests would crash every time a mocked subclass was dealloced by ARC.

Solution is to call the correct init method on CLBeacon. Looking here we see that there is an addition init method. Declare it in a category in your code.

@interface CLBeacon (PRXInternal)

- (id)initWithProximityUUID:(id)arg1 major:(id)arg2 minor:(id)arg3 proximity:(long long)arg4 accuracy:(double)arg5 rssi:(long long)arg6 ;

@end

Call this initializer if you need an instance of the class. Do not include in production code.

查看更多
登录 后发表回答