Протокол UIAppearance появился в iOS 5 в 2011 году, в те далёкие времена, когда у Instagram не было приложения под Android, а сериальному Неду Старку ещё не отрубили голову.
Мейстеры мне прислали ворона с новостью, что на момент выхода iOS 5 — уже отрубили. Но чтобы не спойлерить красную свадьбу или что-то ещё, пожалуй, оставлю всё как есть.
Информации, туториалов, статей на эту тему достаточно, каждый начинающий iOS разработчик знает как и зачем его применять, так что эта статья не об этом. Я бы хотел поразмышлять на тему, что с ним, на мой взгляд, не так, и почему Apple на это не обращает внимания.
В качестве небольшой вводной — выдержки из документации, которая всегда была, есть и должна быть основным доверенным источником информации.
You can customize the appearance of instances of a class by sending appearance modification messages to the class’s appearance proxy.
To support appearance customization, a class must conform to the UIAppearanceContainer protocol and relevant accessor methods must be marked with UI_APPEARANCE_SELECTOR
Для себя я понимаю это так: если хочешь изменить внешний вид по умолчанию для всех объектов класса, реализующего UIAppearance, проверь, помечено ли свойство с помощью UI_APPEARANCE_SELECTOR, и вперёд. Соответственно, если свойство не является UI_APPEARANCE_SELECTOR, то это сделать не получится.
Но "не получится" не значит "нельзя попытаться", поэтому я предлагаю всем любопытным провести простой эксперимент: откройте первый попавшийся проект и добавьте в метод application:didFinishLaunchingWithOptions:
следующую строчку:
UIView.appearance().isHidden = true
Прикиньте, что произойдёт, и запустите.
Я, как зануда, ожидал бы возможные варианты:
- ничего не происходит;
- ничего не происходит, но в консоль вываливается лог типа "isHidden is not UI_APPEARANCE_SELECTOR, stupid";
- приложение ловит критическую ошибку или ассерт с подобным сообщением.
Но нет, всё, включая основное окно приложения, становится скрытым. С одной стороны, это даже логично — что написано, то и сделано. Но с другой стороны это выглядит как недокументированное поведение и, как мне кажется, немаленькая такая дыра.
Я ещё мог бы смириться с тем, если бы такие фокусы можно было проворачивать только с теми свойствами, которые влияют на внешний вид, но это можно делать со всеми свойствами!
Например, добавив в код, который используют другие проекты в качестве сторонней библиотеки, вот такую строчку, которая иногда вызывается в рандомный момент времени:
UITableView.appearance().delegate = nil
можно обнулить все делегаты у всех таблиц, которые появятся на экране после выполнения этого кода.
Разработчики получат много удовольствия, пытаться понять, что случилось! Наверняка, можно придумать и что-то ещё более забавное!
Я очень надеюсь, что подобные вещи всё-таки не остались без внимания Apple (информации на эту тему, правда, я не нашёл), и подобные фокусы вскрываются где-нибудь на этапе автоматической проверки сборки в AppstoreConnect. Но проверять, если честно, не хочется.
Такие дела, ребята. Буду рад дискуссии, если тема кому-то тоже интересна.
P. S. Верните мне мой 2011!