Быстрые советы: конфигурация свойств

Если вы какое-то время занимались разработкой iOS, вы встречали большие init и viewDidLoad() методы, которые выглядят примерно так:

class MyViewController: UIViewController {
  var collectionView: UICollectionView?
  override func viewDidLoad() {
    super.viewDidLoad()
  
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
  
    collectionView = UICollectionView(frame: .zero,  
                                    collectionViewLayout: layout)
    collectionView?
      .translatesAutoresizingMaskIntoConstraints = false
    collectionView?.isPagingEnabled = true
    collectionView?.backgroundColor = .clear
    collectionView?.showsHorizontalScrollIndicator = false
    view.addSubview(collectionView!)
    // Auto Layout Code …
  }
}

Мы можем добиться большего благодаря способности Swift настраивать свойства, встроенные в закрытие.

class MyViewController: UIViewController {
let collectionView: UICollectionView = {
    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.scrollDirection = .horizontal
    let collectionView = UICollectionView(
      frame: .zero, 
      collectionViewLayout: flowLayout
    )
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    collectionView.isPagingEnabled = true
    collectionView.backgroundColor = .clear
    collectionView.showsHorizontalScrollIndicator = false
    return collectionView
  }()
// MARK: - Lifecycle
override func viewDidLoad() {
    super.viewDidLoad()
view.addSubview(collectionView)
    // Auto Layout Code ...
 }
}

Теперь viewDidLoad() содержит только код, имеющий непосредственное отношение к загрузке представления, вся конфигурация свойств централизована, а ее объем значительно сокращен. У нас также есть гарантии существования нашего свойства представления коллекции.

Но мы можем сделать даже лучше. Возможно, мы хотим повторно использовать ту же конфигурацию представления коллекции в другом месте нашего приложения. Мы можем расширить UICollectionView с помощью удобного инициализатора и полностью реорганизовать наш код конфигурации вне нашего контроллера представления.

extension UICollectionView {
  convenience init(
    flowLayoutScrollDirection: UICollectionViewScrollDirection) {
    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.scrollDirection = flowLayoutScrollDirection
    self.init(frame: .zero, collectionViewLayout: flowLayout)
    translatesAutoresizingMaskIntoConstraints = false
    isPagingEnabled = true
    backgroundColor = .clear
    showsHorizontalScrollIndicator = false
  }
}
class MyViewController: UIViewController {
  let collectionView = UICollectionView(flowLayoutScrollDirection: .horizontal)
  // MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(collectionView)
    // Auto Layout Code ...
  }
}

Сейчас это довольно чисто, но нам еще есть над чем работать. Все свойства экземпляра, объявленные как константы (т.е. let), инициализируются при создании объекта, поэтому наше представление коллекции инициализируется во время инициализации контроллера представления. Если у вас есть множество let свойств, которые дорого настраивать (например, множество настраиваемых пользовательских интерфейсов или объектов источников данных), это может привести к значительному увеличению объема используемой памяти. К счастью, у нас есть простое решение: отложенная загрузка.

Ленивая загрузка - это стратегия загрузки вещей только при первом обращении к ним. В нашем примере нам нужно загрузить представление коллекции только тогда, когда мы пытаемся добавить его в иерархию представлений. Реализовать это очень просто.

class MyViewController: UIViewController {
  lazy var collectionView = UICollectionView(flowLayoutScrollDirection: .horizontal)
// MARK: - Lifecycle
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(collectionView)
    // Auto Layout Code ...
  }
}

Это намного лучше! Вы можете заметить, что наше представление коллекции больше не является постоянным. На момент написания этой статьи не было возможности создать свойство экземпляра константы с отложенной загрузкой. Однако этот простой обходной путь должен помочь ограничить область действия установщика этого свойства:

private(set) lazy var collectionView = UICollectionView(…)

Теперь наше свойство представления коллекции может быть установлено только в рамках основной реализации контроллера представления (то есть class MyViewController: UIViewController { … }). Если вы организуете свой код с помощью расширений, части вашего контроллера представления, которые имеют доступ к установщику, будут значительно ограничены. Это не идеальное решение, но оно работоспособное. Константы, объявленные статически или в глобальной области видимости, автоматически загружаются с отложенной загрузкой.

Подобная настройка свойств поможет сохранить ваш код гибким и легким для чтения, оптимизируя при этом производительность.

В нашей следующей статье мы рассмотрим, как включить ленивые последовательности в Swift.

Чтобы получить больше информации о дизайне и разработке, подпишитесь на BPXL Craft и подпишитесь на Black Pixel в Twitter.

Black Pixel - агентство по созданию креативных цифровых продуктов. Узнайте больше на blackpixel.com.