Skip to content

Conversation

@alexandrius
Copy link
Contributor

@alexandrius alexandrius commented Nov 21, 2024

Hello. This PR changes [RCTBridge currentBridge] to the bridge instance the ViewManager was created. For example react-native-threads creates its own bridge for process separation.

Thanks for all amazing work @chrfalch @wcandillon

@alexandrius alexandrius changed the title fix: polluted currentBridge fix: polluted [RCTBridge currentBridge] Nov 21, 2024
@alexandrius
Copy link
Contributor Author

I have signed the CLA!

@wcandillon
Copy link
Contributor

@Kudo Thank you for looking into this. Here are the two comments that came up:

  • Make the originalBridgeInstance a weak reference to avoid retaining the React instance from native modules.
  • Consider renaming originalBridge to bridge, as the "original" prefix might not be necessary.

@wcandillon
Copy link
Contributor

@Kudo @alexandrius is this potentially a fix for #2039?

@Kudo
Copy link
Contributor

Kudo commented Dec 4, 2024

sorry for late to share comment here. i don't like the singleton actually but i didn't find a better way in fabric.
this is my proposed change:

  • we can get bridge from old arch ViewManager, so we don't need to access singleton.
  • accessing singleton bridge actually equals to accessing singleton SkiaManager. i turn to provide a SkManager rather than bridge.
  • keeps the singleton weak to prevent retain cycle.
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomView.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomView.mm
index 1f1bdb5..bc0831a 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomView.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomView.mm
@@ -24,10 +24,10 @@ using namespace facebook::react;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   if (self = [super initWithFrame:frame]) {
-    auto skManager = [[self skiaManager] skManager];
-    // Pass SkManager as a raw pointer to avoid circular dependenciesr
+    // Pass SkManager as a raw pointer to avoid circular dependencies
+    auto skManager = [SkiaManager latestActiveSkManager].get();
     [self
-        initCommon:skManager.get()
+        initCommon:skManager
            factory:[](std::shared_ptr<RNSkia::RNSkPlatformContext> context) {
              return std::make_shared<RNSkiOSView<RNSkia::RNSkDomView>>(context);
            }];
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomViewManager.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomViewManager.mm
index 30f53eb..d77f3b8 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomViewManager.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaDomViewManager.mm
@@ -15,7 +15,8 @@
 RCT_EXPORT_MODULE(SkiaDomView)
 
 - (SkiaManager *)skiaManager {
-  auto bridge = [RCTBridge currentBridge];
+  auto bridge = self.bridge;
+  RCTAssert(bridge, @"Bridge must not be nil.");
   auto skiaModule = (RNSkiaModule *)[bridge moduleForName:@"RNSkiaModule"];
   return [skiaModule manager];
 }
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.h b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.h
index 8f5457f..07d41dc 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.h
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.h
@@ -16,4 +16,10 @@
                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)
                                    jsInvoker;
 
+#ifdef RCT_NEW_ARCH_ENABLED
+// Fabric components do not have a better way to interact with TurboModules.
+// Workaround to get the SkManager instance from singleton.
++ (std::shared_ptr<RNSkia::RNSkManager>)latestActiveSkManager;
+#endif // RCT_NEW_ARCH_ENABLED
+
 @end
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.mm
index 7d3cf59..b32ea39 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaManager.mm
@@ -8,6 +8,8 @@
 
 #import "RNSkiOSPlatformContext.h"
 
+static __weak SkiaManager *sharedInstance = nil;
+
 @implementation SkiaManager {
   std::shared_ptr<RNSkia::RNSkManager> _skManager;
   __weak RCTBridge *weakBridge;
@@ -29,6 +31,7 @@
                                    jsInvoker {
   self = [super init];
   if (self) {
+    sharedInstance = self;
     RCTCxxBridge *cxxBridge = (RCTCxxBridge *)bridge;
     if (cxxBridge.runtime) {
 
@@ -45,4 +48,18 @@
   return self;
 }
 
+- (void)dealloc
+{
+  sharedInstance = nil;
+}
+
+#ifdef RCT_NEW_ARCH_ENABLED
++ (std::shared_ptr<RNSkia::RNSkManager>)latestActiveSkManager
+{
+  if (sharedInstance != nil) {
+    return [sharedInstance skManager];
+  }
+  return nullptr;
+}
+#endif // RCT_NEW_ARCH_ENABLED
 @end
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureView.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureView.mm
index 9bf2f61..b0730f6 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureView.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureView.mm
@@ -24,9 +24,9 @@ using namespace facebook::react;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   if (self = [super initWithFrame:frame]) {
-    auto skManager = [[self skiaManager] skManager];
-    // Pass SkManager as a raw pointer to avoid circular dependenciesr
-    [self initCommon:skManager.get()
+    // Pass SkManager as a raw pointer to avoid circular dependencies
+    auto skManager = [SkiaManager latestActiveSkManager].get();
+    [self initCommon:skManager
              factory:[](std::shared_ptr<RNSkia::RNSkPlatformContext> context) {
                return std::make_shared<RNSkiOSView<RNSkia::RNSkPictureView>>(
                    context);
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureViewManager.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureViewManager.mm
index 8ebccb1..c123db1 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureViewManager.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaPictureViewManager.mm
@@ -15,7 +15,8 @@
 RCT_EXPORT_MODULE(SkiaPictureView)
 
 - (SkiaManager *)skiaManager {
-  auto bridge = [RCTBridge currentBridge];
+  auto bridge = self.bridge;
+  RCTAssert(bridge, @"Bridge must not be nil.");
   auto skiaModule = (RNSkiaModule *)[bridge moduleForName:@"RNSkiaModule"];
   return [skiaModule manager];
 }
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.h b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.h
index 8335d42..c3fb2e2 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.h
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.h
@@ -29,7 +29,6 @@
            factory:(std::function<std::shared_ptr<RNSkBaseiOSView>(
                         std::shared_ptr<RNSkia::RNSkPlatformContext>)>)factory;
 - (std::shared_ptr<RNSkBaseiOSView>)impl;
-- (SkiaManager *)skiaManager;
 
 - (void)setDebugMode:(bool)debugMode;
 - (void)setOpaque:(bool)opaque;
diff --git a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.mm b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.mm
index 8ec714e..2dbe373 100644
--- a/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.mm
+++ b/node_modules/@shopify/react-native-skia/ios/RNSkia-iOS/SkiaUIView.mm
@@ -48,12 +48,6 @@
   _factory = factory;
 }
 
-- (SkiaManager *)skiaManager {
-  auto bridge = [RCTBridge currentBridge];
-  auto skiaModule = (RNSkiaModule *)[bridge moduleForName:@"RNSkiaModule"];
-  return [skiaModule manager];
-}
-
 - (void)willInvalidateModules {
   _impl = nullptr;
   _manager = nullptr;
@@ -110,7 +104,7 @@
     // this flag is only set when the view is inserted and we want to set the
     // manager here since the view could be recycled or the app could be
     // refreshed and we would have a stale manager then
-    _manager = [[self skiaManager] skManager].get();
+    _manager = [SkiaManager latestActiveSkManager].get();
   }
 }
 #endif // RCT_NEW_ARCH_ENABLED

@Kudo
Copy link
Contributor

Kudo commented Dec 4, 2024

@Kudo @alexandrius is this potentially a fix for #2039?

not pretty sure for this. i cannot repro this issue previously.

@alexandrius
Copy link
Contributor Author

@Kudo @alexandrius is this potentially a fix for #2039?

It doesn't look like the same issue to me.

@wcandillon @Kudo

I'm a bit confused with the patch, are you planning to refactor it with a different approach? Should I close this PR?

@Kudo
Copy link
Contributor

Kudo commented Dec 6, 2024

@alexandrius i would like to keep your pr ongoing since you are the first one raise the issue and propose a solution. so please try to update this pr if my patch makes sense to you. the whole idea of my patch is to move away [RCTBridge currentBridge] as much as possible. if there's anything unclear to you, please feel free to let me know and i can explain further. thanks again for your help.

@alexandrius
Copy link
Contributor Author

@Kudo @wcandillon Updated to @Kudo's patch. Tested works fine

Copy link
Contributor

@Kudo Kudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. just having some out-of-sync change and should be good to merge. thanks @alexandrius

@wcandillon wcandillon merged commit 2cfa890 into Shopify:main Dec 9, 2024
8 checks passed
@github-actions
Copy link
Contributor

🎉 This PR is included in version 1.7.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

stevengoldberg pushed a commit to stevengoldberg/react-native-skia that referenced this pull request May 18, 2025

---------

Co-authored-by: William Candillon <[email protected]>
Co-authored-by: Kudo Chien <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants