Спецификатор формата, такой как `%15@`, работает в NSLog, но не с NSString stringWithFormat.

Я обнаружил кое-что странное при попытке использовать спецификаторы ширины с %@. Они отлично работают в NSLog, но не в NSString stringWithFormat:.

Пример:

NSString *rightAligned = @"foo";
NSString *leftAligned = @"1";

NSLog(@"| %15@ | %-15@ |", rightAligned, leftAligned);

И вы получите ожидаемый результат:

|             foo | 1               |

Но замените NSLog на stringWithFormat::

NSString *test = [NSString stringWithFormat:@"| %15@ | %-15@ |", rightAligned, leftAligned];

И значение test неверно:

| foo | 1 |

Если я изменю это, чтобы использовать %s и cStringUsingEncoding:, тогда это сработает:

NSString *test2 = [NSString stringWithFormat:@"| %15s | %-15s |", [rightAligned cStringUsingEncoding:NSUTF8StringEncoding], [leftAligned cStringUsingEncoding:NSUTF8StringEncoding]];

Результат такой же, как с NSLog.

Что делает это действительно странным, так это то, что NSLog в основном просто оболочка вокруг NSString stringWithFormat:.

Так почему разные результаты? Почему спецификаторы формата не учитываются для %@ в stringWithFormat, но они учитываются в NSLog?

В качестве примечания: инициализатор Swift String init(format:) имеет ту же проблему со спецификаторами %@ и ширины.


person rmaddy    schedule 01.05.2019    source источник
comment
NSLog теперь в большинстве случаев является просто прокладкой для os_log. источник: Примечания к выпуску Foundation для macOS 10.12 и iOS 10   -  person Willeke    schedule 02.05.2019


Ответы (1)


Загадка заключается в том, почему %15@ всегда работает. Не должно.

Спецификаторы формата происходят от sprintf, у которого нет %@ (это просто специальное расширение для Objective-C). Что касается stringWithFormat, то %15s всегда было способом сказать это; Я могу привести примеры переполнения стека, такие как NSString stringwithformat: заполнение 2 строк неизвестным длина.

Я предполагаю, что он «работает» только потому, что теперь он использует os_log под капотом; к сожалению, синтаксис os_log почти полностью недокументирован.

person matt    schedule 08.05.2019
comment
Я подозреваю, что если вы попробуете это с достаточно старой версией Xcode, вы обнаружите, что поведение NSLog соответствует stringWithFormat поведению. - person matt; 08.05.2019
comment
Я понимаю, почему %15s работает. Вопрос в том, почему %15@ работает в NSLog, а не NSString stringWithFormat:. - person rmaddy; 08.05.2019
comment
Вопрос в том, почему %15@ работает в NSLog. Да, и я говорю, что не знаю, потому что не должен. :) Я предполагаю, что это потому, что теперь он использует os_log под капотом; к сожалению, синтаксис os_log почти полностью недокументирован. - person matt; 08.05.2019