Известный закон Джеймса Завински гласит “Каждая программа пытается расширяться до тех пор, пока не сможет читать почту”.
В данном докладе будут рассмотрены следующие практические аспекты, возникшие при разработке популярного почтового клиента Spark (номинант “App Store Best Of 2015”):
- Высоконагруженные интерфейсы: рендеринг цепочек сообщений и списка писем — ключевых элементов почтового приложения с высокими требованиями к производительности. Разбор подходов, использующих UIKit, CoreText, AsyncDisplayKit, Core Graphics.
- Базы данных и поиск: работа с большими SQLite базами, оптимизация SQL-запросов, производительность полнотекстового поиска, опыт перехода с SQLite FTS4 на SQLite FTS5.
- Ускоряем Core Foundation: техники кэширования, производительность регулярных выражений, использование альтернативных библиотек (expat, libxml, libcurl), разгрузка applicationDidFinishLaunching, эффективная работа с многопоточностью.
- Работа в фоновом режиме и сетевое взаимодействие: энергосбережение с использованием облачной инфраструктуры; асимметричное шифрование почтовых сообщений; поддержка HTTP/2 для REST API, результаты тестирования алгоритма сжатия LZFSE.
Помимо практических аспектов, в докладе будет уделено внимание используемой в Spark методологии тестирования производительности и энергопотребления.
2. .
• PDF Expert, Scanner Pro,
Documents, Calendars, Spark,
Printer Pro, Fluix
• 6 больших iOS/macOS
кодовых баз; большей частью
ObjC, в новых проектах Swift
3. • Почтовый клиент
• Кодовое название SmartMail
• Начата разработка в феврале 2014 года
• Первый релиз 29 мая 2015
10. Performance Tests
- [XCTest measureBlock:]
• установить baseline!
- [RDTestCase measureBlock: limit:]
• Проверка прямо в коде
• Защита от разницы на порядок
• Тесты UI
• Общее время выполнения
15. UICollectionView + UILabel + Autolayout
Считает ширину/высоту
Собирает элементы в письмоСобирает список писем, нужна
высота UICollectionViewCell
Все работает на Main Thread
16. 0
0.5
1
1.5
2
2.5
3
100 200 300 400
Время, сек.
Количество View
Производительность Autolayout
Источник: Флориан Куглер, http://bit.ly/2fhJbwB
17. Ручной layout
• Считаем frame всех view
• Оценка размера текста с помощью UILabel
• Меньше связей, чем с Auto-Layout => быстрее
• Много кода layout
• Простор для улучшения
20. Background поток
• ASTextNode
• Измерение ширины текста (TextKit)
• Рендер текста
• ASImageNode
• Загрузка/декодирование изображения
• Layout
• Похож на FlexBox
26. UITableView + UITableViewCell
• Оптимизация для GPU медленных устройств
• От множества UIView к -[UIView drawRect:]
• Влияет на скорость создания таблицы
• Большой метод -drawRect
29. Оптимизация регулярных выражений
(альтернативные группы)
(?>to|кому|a[n]?|à|til[l]?|para|À|destinataire|Pour)[^Sn]*+:
(?=[tкaàtpÀdP])(?>to|кому|a[n]?|à|til[l]?|para|À|destinataire|Pour)[^Sn]*+:
На 30% быстрее!
Было
Стало c выносом первой буквы из альт. групп
31. Оптимизация регулярных выражений
(Remove case-insensitive)
(?i)(?=[tкaàtpÀd])(?>to|кому|a[n]?|à|til[l]?|para|À|destinataire|Pour)[^Sn]*+:(?-i)
(?=[tкaàtpÀd])(?>to|кому|a[n]?|à|til[l]?|para|À|destinataire|Pour)[^Sn]*+:
На 60% быстрее, тест: 1000 раз подряд, 1280 байт текст
Было
Стало без (?i)
35. Проблемы с FTS4
• Язык запросов
• Не полная поддержка AND, OR, NOT в MATCH
• Долгое «прогревание» при первом запросе
• Задержки до 10+ секунд при индексировании
• Нагрузка на IO / CPU
• Релевантность (?)
36. SQLite FTS5
CREATE VIRTUAL TABLE IF NOT EXISTS messagesfts USING fts4(messagePk,
messageFrom, messageTo, subject, searchBody, tokenize=unicode61)
CREATE VIRTUAL TABLE IF NOT EXISTS messagesfts USING fts5 (messagePk,
messageFrom, messageTo, subject, searchBody)
37. SQLite FTS5
• SQLite 3.9 + SQLITE_ENABLE_FTS5
• Нет задержек при индексировании (быстро!)
• Улучшенный язык запросов
~ 17%
• Скорость поиска:
FTS4
FTS5
38. Трюки SQLite
• Несколько баз
• Задержка при индексировании/поиска не влияет на основную базу
• Миграции
• ADD COLUMN — бесплатен
• Пересоздание таблицы для других изменений
• Несколько баз
• C-функции в SQLite
• atomic_write: +10% к записи на iOS
41. HTTP vs IMAP
• TCP / TLS — так же
• Больше времени на авторизацию, выбор папки
• XOAuth
• Не поддерживается NSURLSession
• Постоянный обмен короткими пакетами
• Polling / long-polling: NOOP/ IDLE
46. Загрузка писем по HTTP
• Тело письма (<2Мб) скачивается нашей инфраструктурой и
шифруется публичным ключом девайса
• Пуш-сообщение содержит ссылку на зашифрованное письмо
• Тело письма скачивается Push Service Extension
• …
• PROFIT!
48. HTTP/2
• HTTP/2 быстрее HTTP/1.1
• Поддерживается, начиная с iOS 9
• Более эффективен в мелочах
• Мультиплексирование
49. LZFSE
• Алгоритм от Apple
• Open Source (github)
• ~ 40% быстрее ZLIB
• Spark: экономия ~ 1 секунды CPU времени
• Альтернативы: bzip2, brotli
• Время сжатия на сервере?
Всем привет, спасибо что пришли. Я тех-директор Readdle, мы делаем приложения для iOS чуть больше времени чем существует iOS.
Возможно вы слышали про некоторые из наших популярных приложений. У нас в компании 6 больших iOS кодовых баз, исторически мы используем Objective-C и с прошлого года начинаем новые проекты на Swift.
В этом докладе я буду рассказывать про наш почтовый клиент Spark. Заранее прошу прощения у тех, кто пришел послушать про Open Source проект обработки данных Apache Spark с которым мы только делим общее название. Мы решили делать наш Спарк в 14 году для проверки наших идей по улучшению UX, автоматизации работы с почтой и, потенциально — машинного обучения. В течении первого года разработки, мы называли приложениие СмартМэил — мы строим почту более «умную» чем стандартную.
Поскольку на iOS уже есть стандартный почтовый клиент; то единственный способ выпустить успешное новое почтовое приложение — это «убить» для конкретного пользователя стандартный Mail.app. Заставить пользователя переключится — сложно.
Мы не делаем самое быстрое в мире приложение — основной наш фокус для другой функциональности которая приносит людям пользу — умные оповещения, управления письмами и организация работы с почтой. Но если приложение будет не достаточно быстрым — на него не перейдут.
Как мы определяем «достаточно быстро»? Субъективно, с помощью Xcode и запуская тесты.
Для хранения писем с самого начала работы мы выбрали стандартный SQLite и решили отказаться от каких-либо ORM, которые создают дополнительные непрозрачные слои при работе с данными. Для удобства интеграции с Obj-C, мы так же используем FBDB — библиотеку которая позволяет использовать Foundation типы данных (NSString) при работе с SQLite.