React Native向Swift原生组件传递UIFont对象后值不匹配的问题求助
问题原因分析
你碰到的核心问题是React Native和iOS原生之间的桥接层不会自动把JS端的普通字典转换成UIFont对象。当你在RN端传递{name: "Arial", size: 15}这样的对象时,Objective-C的RCT_EXPORT_VIEW_PROPERTY默认没有内置这种结构到UIFont的转换逻辑,桥接层无法识别你的配置,就会自动 fallback 到iOS系统的默认字体(也就是你看到的.SFUI-Regular 14pt),所以你设置的字体和大小根本没被正确解析。
解决方案
下面提供两种可行的解决方式,你可以根据自己的需求选择:
方案一:手动解析字典(简单直接)
这种方式是把JS端传递的对象作为字典接收,在Swift端手动解析并创建UIFont:
- 修改Objective-C的属性暴露代码:
把属性类型从UIFont改成NSDictionary:
@interface RCT_EXTERN_MODULE(RCTNativeSwiftViewManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(uiFontStyle, NSDictionary) @end
- 更新Swift端的属性处理逻辑:
将属性改为可选字典类型,在didSet中解析并创建字体:
@objc var uiFontStyle: NSDictionary? { didSet { guard let fontDict = uiFontStyle, let fontName = fontDict["name"] as? String, let fontSize = fontDict["size"] as? CGFloat else { // 处理无效输入,用默认字体兜底 self.font = UIFont.systemFont(ofSize: 14) print("Invalid font parameters, using default font") return } // 尝试创建指定字体,不存在则用同字号的系统字体兜底 if let targetFont = UIFont(name: fontName, size: fontSize) { self.font = targetFont print("Did set: ", targetFont) } else { print("Font \(fontName) not found, using system font with size \(fontSize)") self.font = UIFont.systemFont(ofSize: fontSize) } } }
方案二:自定义桥接转换器(更优雅)
如果你希望保持UIFont作为属性类型,可以通过扩展RCTConvert来告诉桥接层如何将JS字典转换为UIFont:
- 创建RCTConvert的扩展文件:
新建一个Objective-C文件(比如RCTConvert+UIFont.m),添加以下代码:
#import <React/RCTConvert.h> @implementation RCTConvert (UIFont) + (UIFont *)UIFont:(id)json { if ([json isKindOfClass:[NSDictionary class]]) { NSString *fontName = [self NSString:json[@"name"]]; CGFloat fontSize = [self CGFloat:json[@"size"]]; // 优先使用指定字体,不存在则用同字号系统字体 return [UIFont fontWithName:fontName size:fontSize] ?: [UIFont systemFontOfSize:fontSize]; } // 输入无效时返回默认字体 return [UIFont systemFontOfSize:14]; } @end
- 保持原有的Objective-C属性暴露:
还是用UIFont作为属性类型:
@interface RCT_EXTERN_MODULE(RCTNativeSwiftViewManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(uiFontStyle, UIFont) @end
- 优化Swift端的属性定义:
建议把属性改为可选类型,避免强制解包的风险:
@objc var uiFontStyle: UIFont? { didSet { if let validFont = uiFontStyle { self.font = validFont print("Did set: ", validFont) } } }
额外注意事项
- 确保你指定的字体在iOS系统中存在:比如Arial是iOS自带的,但如果是自定义字体,需要在
Info.plist中添加Fonts provided by application项,把字体文件路径配置进去,否则会 fallback 到系统字体。 - JS端传递的
size必须是数字类型,桥接层会自动转换为iOS的CGFloat,如果传递字符串会导致解析失败。
内容的提问来源于stack exchange,提问作者stef000
相关产品推荐
相关产品推荐

