我在iOS16中遇到了一个错误:当一个本地化字符串从Swift传递到Objective,并与另一个相同的本地化字符串(在Objective中定义)进行比较时,结果可能是假的,参数顺序可能会影响结果。见演示:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let tc = TestClass()
tc.receive(NSLocalizedString("Start", comment:""))
}
}
@implementation TestClass
- (void)receive:(NSString *)swiftString {
NSString *objcString = NSLocalizedString(@"Start", @"");
BOOL result1 = [swiftString isEqualToString:objcString];
BOOL result2 = [objcString isEqualToString:swiftString];
NSLog(@"result: %d, %d", result1, result2);
}
@end
它是可本地化的(以日语为例,但除拉丁文以外的任何书写系统都可以复制bug):
"Start" = "開始";
产出:
result: 0, 1
我们不知道其根本原因是NSLocalizedString()
还是-isEqualToString
。这种情况在iOS15上不会发生。
还有其他人遇到过这个错误吗?
发布于 2022-10-18 07:37:45
这看起来肯定像一个bug,我可以在Xcode iOS 16模拟器中再现它。调试器显示
NSString *objcString = NSLocalizedString(@"Start", @"");
是_NSBPlistMappedString
的一个实例,它是NSString
的一个未记录的子类。
(lldb) p objcString
(_NSBPlistMappedString *) $1 = 0x8230ceeb696930f7
(lldb) p [objcString superclass]
(Class) $2 = NSString
显然,在iOS 16中没有正确实现Swift字符串与该子类实例的比较。
解决方法1:使用compare
而不是isEqualToString
NSString *objcString = NSLocalizedString(@"Start", @"");
BOOL result1 = [swiftString compare:objcString] == NSOrderedSame;
BOOL result2 = [objcString compare:swiftString] == NSOrderedSame;
NSLog(@"result: %d, %d", result1, result2);
// result: 1, 1
解决方法2:确保objcString
是NSString
的一个实例
NSString *objcString = @(NSLocalizedString(@"Start", @"").UTF8String);
BOOL result1 = [swiftString isEqualToString:objcString];
BOOL result2 = [objcString isEqualToString:swiftString];
NSLog(@"result: %d, %d", result1, result2);
// result: 1, 1
当然,这两种解决办法都不是很令人满意。正如注释中所建议的,错误应该是向苹果报告。
https://stackoverflow.com/questions/74093430
复制相似问题