Concerns about init not being called, and allocWithZone being misused as a singleton, in the iOS Obj-c code
Hi all,
I've been trying to delve into RNCallKeep to understand some things, and came across this which I thought might be worth bringing to your attention:
https://github.com/react-native-webrtc/react-native-callkeep/blob/db693d5b6a0a3c38b5d645fd53fc37801d016742/ios/RNCallKeep/RNCallKeep.m#L205
- In
setup, it calls 'alloc' but does not 'init'. - This is not the way things are done in Obj-C, according to Apple "You must use an init... method to complete the initialization process": https://developer.apple.com/documentation/objectivec/nsobject/1571958-alloc
- allocWithZone is just there for historical reasons, idiomatically this is not to be called, alloc is what should be called.
Delving further, it appears someone has overridden allocWithZone to implement a singleton:
https://github.com/react-native-webrtc/react-native-callkeep/blob/db693d5b6a0a3c38b5d645fd53fc37801d016742/ios/RNCallKeep/RNCallKeep.m#L79
- This is confusing and un-idiomatic: allowWithZone isn't to be used, alloc is
- Also alloc is about allocating new memory, not about managing singletons.
May I suggest a more idiomatic way to implement a singleton in objc is the following:
+ (instancetype)sharedInstance {
static MySingleton *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Please note the importance of calling 'init' in the above singleton.
I did place a breakpoint in 'init' but just got a callstack of incomprehensible RN C++ - I don't know what's calling this, and it concerns me that this is not being done properly.
Any chance that this could be improved? I could raise a PR but if so i'd love the feedback of the authors as to how this is (or if it is?) actually being inited currently and how to fix that too, or we might end up initing twice somehow.
Thanks all :)
A noted consequence of the current initialisation behaviour is that on rare occasions, when an iOS app is in a terminated state and launched via a VOIP notification, the RNCallKeepDidDisplayIncomingCall + RNCallKeepPerformAnswerCallAction events are added to _delayedEvents prior to the array being initialised (due to init not having been called yet), resulting in the loss of the events.