Skip to content

fix(ios): install ubiquity observer only after emitter callback is bound#61

Open
mariusvanwyk wants to merge 1 commit into
kuatsu:masterfrom
mariusvanwyk:fix/ios-emit-before-callback-bound
Open

fix(ios): install ubiquity observer only after emitter callback is bound#61
mariusvanwyk wants to merge 1 commit into
kuatsu:masterfrom
mariusvanwyk:fix/ios-emit-before-callback-bound

Conversation

@mariusvanwyk
Copy link
Copy Markdown

Summary

Fixes #59.

RCTCloudStorageCloudKit registered its NSUbiquityIdentityDidChangeNotification observer in -init, but the observer's block ends up calling the codegen-generated -emitOnCloudAvailabilityChanged:, which invokes a std::function event-emitter callback that is only bound later via -setEventEmitterCallback:.

If iOS posts the ubiquity-change notification in the window between -init and -setEventEmitterCallback: (e.g. on app launch after a reboot, when the user signs in/out of iCloud, or when iCloud Drive is toggled), the block invokes an empty std::function, throwing std::bad_function_call and terminating the process with SIGABRT.

Fix

Move the observer installation into -setEventEmitterCallback: so it is only installed once the emitter callback is bound. -dealloc already removes the observer via the stored token, so no change needed there. The existing "emit current availability immediately after binding" behavior is preserved (we still call emitCloudAvailabilityChanged at the end of -setEventEmitterCallback:).

This matches the implementation approach proposed by @ayousufi in #59.

Crash confirmation

Two independent reports against react-native-cloud-storage@3.0.0 on iOS (New Architecture / Turbo Modules):

Exception Type: EXC_CRASH (SIGABRT)

 9 App  std::__1::__throw_bad_function_call[abi:ne200100]() + 52
10 App  std::__1::__function::__value_func<void (...)>::operator()(...) + 4
11 App  std::__1::function<void (...)>::operator()(...) + 92
12 App  -[NativeCloudStorageCloudKitIOSSpecBase emitOnCloudAvailabilityChanged:] + 64
13 App  -[RCTCloudStorageCloudKit emitCloudAvailabilityChanged] + 188
14 App  __31-[RCTCloudStorageCloudKit init]_block_invoke + 28
15 CoreFoundation  __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
...
19 Foundation      -[NSNotificationCenter postNotificationName:object:userInfo:]
20 Foundation      ___postUbqiuityAccountChangeNotification_block_invoke

Reproduced on:

Testing

  • Before: on a device that had iCloud state change recently, the app reliably crashes within seconds of launch. Also reproducible by toggling iCloud Drive off/on in Settings while the app is foregrounded.
  • After: no crash in the same scenarios. The first emit after JS binds its listener still delivers the current availability correctly (because setEventEmitterCallback: continues to call emitCloudAvailabilityChanged at the end).

Notes

  • Android is unaffected — its module does not use an equivalent NSNotificationCenter-style observer.
  • No API or JS-side change.

The NSUbiquityIdentityDidChangeNotification observer was being registered
in -init, but its block calls emitCloudAvailabilityChanged, which
delegates to the codegen-generated emitOnCloudAvailabilityChanged:. That
invokes a std::function event-emitter callback that is only bound later
via -setEventEmitterCallback:.

If iOS posts the ubiquity-change notification in the window between -init
and -setEventEmitterCallback: (for example on app launch after a reboot,
or when the user toggles iCloud Drive), the block invokes an empty
std::function, throwing std::bad_function_call and terminating the
process with SIGABRT.

Move the observer installation into -setEventEmitterCallback: so it can
only fire after the emitter callback is bound. -dealloc already removes
the observer. The existing 'emit current availability immediately after
binding' behavior is preserved.

Implementation based on the proposal in kuatsu#59.

Fixes kuatsu#59
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 19, 2026

Deploy Preview for react-native-cloud-storage ready!

Name Link
🔨 Latest commit 9611f7a
🔍 Latest deploy log https://app.netlify.com/projects/react-native-cloud-storage/deploys/69e48b7381d0b5000807bd99
😎 Deploy Preview https://deploy-preview-61--react-native-cloud-storage.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@dzeveckij
Copy link
Copy Markdown

merge please 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS: SIGABRT (bad_function_call) when NSUbiquityIdentityDidChangeNotification fires before setEventEmitterCallback binds the emitter

2 participants