可能存在iOS 16中的NSLocalizedString在Swift和Objective-C之间传递时的漏洞

6
我在iOS16中遇到了一个bug:当从Swift传递本地化字符串到Objective-C,与另一个相同的本地化字符串(在Objective-C中定义)进行比较时,结果可能是错误的,并且参数顺序可能会影响结果。请看以下演示:
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

它是可本地化的(以日语为例,但任何拉丁字母以外的书写系统都可以复制这个漏洞):

"Start" = "開始";

输出:

result: 0, 1

我们不知道这个问题的根本原因是来自 NSLocalizedString() 还是 -isEqualToString 。在iOS15上不会出现这种情况。

有其他人遇到过这个错误吗?


4
既然您已经有了一个好的最小可重现示例,并且确实看起来像是一个错误,请向苹果公司提交反馈。 - DarkDust
2
请问您能否将NSLog(@"swiftString: %@", [[swiftString dataUsingEncoding:NSUTF32StringEncoding] debugDescription]);NSLog(@"objcString: %@", [[objcString dataUsingEncoding:NSUTF32StringEncoding] debugDescription]);添加到Objective-C方法中,并显示输出结果? - Martin R
1
2022-10-17 18:50:42.122946+0800 SwiftOC[94706:1197047] swiftString: <fffe0000 ec300000 b3300000 fc300000 c7300000 a3300000 f3300000 b0300000 92300000 8b950000 cb590000> 2022-10-17 18:50:42.123111+0800 SwiftOC[94706:1197047] objcString: <fffe0000 ec300000 b3300000 fc300000 c7300000 a3300000 f3300000 b0300000 92300000 8b950000 cb590000> - 刘maxwell
1个回答

6

这肯定是一个bug,我在Xcode iOS 16模拟器中复现了它。调试器显示通过

NSString *objcString = NSLocalizedString(@"Start", @"");

_NSBPlistMappedString的一个实例,_NSBPlistMappedStringNSString的一个未公开的子类:

(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

解决方法二:确保 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

当然,这两种解决方法都不是非常令人满意。正如评论中建议的那样,应该向苹果报告此错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接