Как реализовать UIView, отображающую фотоаппарат, кастомную иконку или ничего в зависимости от кейса в iOS?
Что проверяют
Умеете ли вы описать состояние вью явно и собрать компонент из готовых кирпичей, а не рисовать всё вручную. Следом обычно спрашивают, как такая вью поведёт себя в ячейке таблицы и в UIStackView, когда показывать нечего.
Как отвечать
Начните с модели. Три взаимоисключающих случая описываются enum Content { case camera, icon(UIImage), none }, а не парой булевых флагов: флаги дают четыре комбинации, и одна из них бессмысленна.
Дальше сама вью:
- внутри
UIImageView: картинку показывает он,contentMode = .scaleAspectFit, констрейнты по краям. Переопределятьdraw(_:)ради показаUIImageне нужно, это дороже и хуже масштабируется; - свойство
contentсdidSet: внутри одинswitch. Для.cameraберётсяUIImage(systemName: "camera"), SF Symbol красится черезtintColor, размер задаётсяUIImage.SymbolConfiguration. Для.iconставится переданная картинка, для.noneimage = nil; - пустое состояние: решите, должна ли вью схлопываться. Если да, выставляйте
isHidden = true, иUIStackViewуберёт её из раскладки. Если размер зависит от содержимого, переопределитеintrinsicContentSizeи вызывайтеinvalidateIntrinsicContentSize()при смене состояния; - доступность:
accessibilityLabelдля камеры и иконки, а для.noneisAccessibilityElement = false, чтобы VoiceOver не останавливался на пустом месте.
Если под «фотоаппаратом» интервьюер имеет в виду живое изображение с камеры, это другой компонент: AVCaptureVideoPreviewLayer поверх AVCaptureSession, запрос разрешения и строка NSCameraUsageDescription в Info.plist. Уточните это до того, как писать код.
Где спотыкаются
Рисуют в draw(_:) и заливают «пустое» состояние серым прямоугольником. Это не «ничего», а заглушка, и вью по-прежнему занимает место.
Забывают про переиспользование. В ячейке состояние от прошлой строки остаётся, пока его не сбросить в prepareForReuse() или не выставлять content при каждой конфигурации.
Меняют состояние из фонового потока, например в колбэке загрузки иконки. Любая работа с UIView идёт на главном потоке, в Swift Concurrency такой код помечают @MainActor.