Возможная ошибка iOS 16 при переходе NSLocalizedString из Swift в Objective-C

Я столкнулся с тем, что я считаю ошибкой в ​​iOS16: когда локализованная строка передается из Swift в Objective-C и сравнивается с другой идентичной локализованной строкой (определенной в Objective-CC), результат может быть ложным, а порядок параметров может повлиять на результат. Смотрите демо:

      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.

Кто-нибудь еще сталкивался с этим багом?

1 ответ

Это определенно похоже на ошибку, я мог бы воспроизвести ее в симуляторе Xcode iOS 16. Отладчик показывает, что строка, полученная

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

является примером_NSBPlistMappedString, недокументированный подкласс:

      (lldb) p objcString
(_NSBPlistMappedString *) $1 = 0x8230ceeb696930f7
(lldb) p [objcString superclass]
(Class) $2 = NSString

По-видимому, сравнение строки Swift с экземплярами этого подкласса реализовано неправильно в iOS 16. Вот два возможных решения:

Обходной путь № 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

Конечно, оба обходных пути не очень удовлетворительны. Как было предложено в комментариях, об ошибке следует сообщить в Apple.

Другие вопросы по тегам