React Native Fabric中RTNViewStreamView单例无法获取已有实例问题
问题分析
- 你创建的单例实例与React Native渲染的实例并非同一对象:在Fabric架构下,RN会根据JSX渲染需求自动调用
initWithFrame:创建RTNViewStreamView实例,而sharedInstance创建的是另一个独立实例,两者内存地址不同,因此修改单例的contentView不会影响界面上的视图。 sharedInstance触发initWithFrame:是UIKit的默认行为:UIView的init方法默认会调用initWithFrame:CGRectZero,这不是单例失效的核心原因,核心问题是实例不匹配。
解决方案
不能通过单例共享Fabric管理的视图实例,推荐以下几种方案:
方案一:保存Fabric创建的实例到全局
在RTNViewStreamView的初始化或视图生命周期方法中,将框架创建的实例保存到静态变量,确保其他类获取到的是RN实际渲染的实例:
@implementation RTNViewStreamView { UIView * _view; } // 新增静态变量保存Fabric创建的实例 static RTNViewStreamView *_sharedFabricInstance = nil; + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider<RTNViewStreamViewComponentDescriptor>(); } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared<const RTNViewStreamViewProps>(); _props = defaultProps; _view = [[UIView alloc] init]; NSLog(@"initWithFrame: %p", _view); self.contentView = _view; // 保存当前Fabric创建的实例 _sharedFabricInstance = self; } return self; } // 修改sharedInstance方法,返回Fabric管理的实例 + (id)sharedInstance { return _sharedFabricInstance; } // 视图销毁时清空全局实例,避免野指针 - (void)dealloc { if (_sharedFabricInstance == self) { _sharedFabricInstance = nil; } } // 其余代码保持不变... @end
注意:如果RN渲染多个RTNViewStreamView实例,此方案只会保存最后创建的那个,仅适用于单实例场景。
方案二:通过视图tag获取实例(支持多实例)
让JS层传递视图的tag到原生模块,再通过Fabric API获取对应实例:
- JS层获取视图tag并传递给原生:
import { findNodeHandle } from 'react-native'; // 假设组件引用为viewRef const viewTag = findNodeHandle(this.viewRef); // 调用原生模块传递tag NativeYourModule.passViewTag(viewTag);
- 原生模块中通过tag获取实例:
#import <React/RCTFabricComponentsRegistry.h> #import <React/RCTComponentViewFactory.h> - (void)passViewTag:(NSNumber *)viewTag { RCTComponentViewFactory *factory = [RCTFabricComponentsRegistry sharedInstance].componentViewFactory; RTNViewStreamView *viewInstance = (RTNViewStreamView *)[factory componentViewWithTag:viewTag.integerValue]; if (viewInstance) { viewInstance.contentView.backgroundColor = [UIColor redColor]; // 执行你的帧解码操作 } }
方案三:抽离解码逻辑到独立单例(更优架构)
如果目的是共享帧解码能力,建议将解码逻辑抽离到独立单例类,让RTNViewStreamView实例持有该单例引用,而非共享视图本身:
// 独立的帧解码单例 @interface FrameDecoder : NSObject + (instancetype)sharedInstance; - (void)decodeFrame:(NSData *)frame targetView:(UIView *)view; @end @implementation FrameDecoder + (instancetype)sharedInstance { static FrameDecoder *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[FrameDecoder alloc] init]; }); return instance; } - (void)decodeFrame:(NSData *)frame targetView:(UIView *)view { // 解码逻辑,解码后更新targetView } @end // 在RTNViewStreamView中使用 @implementation RTNViewStreamView { FrameDecoder *_decoder; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { _decoder = [FrameDecoder sharedInstance]; // 其他初始化操作 } return self; } // 需要解码时调用 - (void)processFrame:(NSData *)frame { [_decoder decodeFrame:frame targetView:_view]; } @end
内容的提问来源于stack exchange,提问作者Stéphane R.
相关产品推荐
相关产品推荐

