Что не так с отображением символов валют в iOS
В июне 2016 года в App Store появилось разработанное нами приложение ИЛЬ ДЕ БОТЭ. Клиент попросил нас использовать шрифт Carisma. К системным шрифтам платформы iOS он не относится, что можно понять после попытки найти его здесь. Работая над приложением, я отметил, что символы валют, попадающие в диапазон от U+20B6 (символ турского ливра) до U+20BE (символ грузинского лари) и набранные шрифтом, не входящим в число системных, снижают производительность приложения. Символ рубля — как раз из указанного диапазона.
Давайте-ка это обсудим.
Разберёмся подробнее, в каких именно ситуациях всё тормозит снижается производительность. Для этого разобьём представление строки с символом валюты на составные части:
Начав комбинировать сущности, я обнаружил, что производительность снижают следующие сочетания:
Эксперимент заключался в измерении нагрузки на процессор при пролистывании списка, элементы которого содержали символ рубля. Средняя нагрузка на процессор для нормального состояния не превышала 10%, а если была проблема, нагрузка колебалась в районе 30–80%, что можно видеть на гифках.
Найдите отличия:
Капитан выходит на связь
Экран справа лагает. Это заметно по показателю загруженности CPU.
Давайте-ка это обсудим.
Разберёмся подробнее, в каких именно ситуациях всё тормозит снижается производительность. Для этого разобьём представление строки с символом валюты на составные части:
- Для отображения используются следующие сущности: UILabel, UITextView и UITextField
- В этих сущностях используются обычная строка NSString и атрибутированная NSAttributedString
- Для строки мы можем получить символ рубля одним из трёх способов:
- Используя HTML:
NSString *htmlString = @"
500 ₽
"; self.string = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil]; - Используя unicode:
self.string = [[NSAttributedString alloc] initWithString: @"500 \u20BD"];
- Используя number formatter:
NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init]; [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; [numberFormatter setCurrencyCode:@"RUB"]; [numberFormatter setMaximumFractionDigits:0]; self.string = [[NSAttributedString alloc] initWithString:[numberFormatter stringFromNumber:@500]];
- Используя HTML:
Начав комбинировать сущности, я обнаружил, что производительность снижают следующие сочетания:
- UILabel, тип строки: attributed, методы получения символа: 2 или 3
- UITextView, тип строки: любой, методы получения символа: любой
- UITextField, тип строки: любой, методы получения символа: любой
Эксперимент заключался в измерении нагрузки на процессор при пролистывании списка, элементы которого содержали символ рубля. Средняя нагрузка на процессор для нормального состояния не превышала 10%, а если была проблема, нагрузка колебалась в районе 30–80%, что можно видеть на гифках.
Чтобы приложение вело себя нормально, нужно избегать тех сочетаний, что я выявил, или использовать для символов валют системный шрифт San Francisco, а также шрифты из семейства Helvetica Neue. Но это минимальные требования. Истинная же причина увеличения нагрузки для меня осталась загадкой, и если кто-то разбирается в сути вопроса — делитесь соображениями в комментариях.
Комментарии (5)
15 ноября 2016 в 13:13
+3↑
↓
А вы пробовали посмотреть, как нарисован символ в используемом шрифте? Может быть там ад из 100500 сплайнов?15 ноября 2016 в 13:13
+1↑
↓
А есть ли в этой несистемной гарнитуре указанные символы?15 ноября 2016 в 14:11
+1↑
↓
Ковырял этот баг в сентябре (ибо такое поведение проявилось только на десятке). Судя по профайлеру корень проблемы в том что размер такого символа считается очень долго. И кстати у меня воспроизводилось и на UILabel с не attributed строкой с Helvetica NeueЧто то типа такого в конечно итоге выходит15 ноября 2016 в 15:01
+1↑
↓
— Вообще-то UITextView/UITextField это поля для редактирования текста и они отлавливают обработку нажатий
— Вы используете NSAttributedString. Этот класc используется для вывода текста со стилями.Попробуйте использовать:
— UILabel с простыми строками NSString
— Можно попробовать через чистый CoreText делать вывод15 ноября 2016 в 15:06
0↑
↓
P.S.
Еще стоит проверить как вы формируете таблицу. Возможно в делегатах таблиц понапихано много всего.
Тестирование стоит проводить на реальном устройстве. Симулятор привязан к железу вашего компа и может давать неверные результаты измерений.