image

Вы наверняка использовали Storyboard или XIB для верстки интерфейсов? Верстать из кода это прекрасно, но иногда намного проще понять как устроен какой-то из компонентов интерфейса, увидев его, а не прочитав. В этой записи я хочу обсудить необходимость использования для IBOutlet модификатора private.

Разработчиков, для которых инкапсуляция IBOutlet является очевидной, тут вряд ли что-то удивит, зато может быть интересен опрос в конце статьи.

Представим, что вы собираетесь создать IBOutlet (ссылку на View с Storyboard) для какого-нибудь из ваших UILabel. При перетаскивании мышкой Xcode заботливо создаст нам что-то вроде

@IBOutlet weak var myLabel: UILabel!

Я долгое время считал эту конструкцию оптимальной, до того момента как мой коллега не спросил — а почему твои IBOutlet не private?

В самом деле, зачем мне оставлять все IBOutlet-ы доступными извне?
Представим себе классическую задачу — у нас есть ячейка, в которой отображается, к примеру, чей-то контакт

import UIKit

class ContactCell: UITableViewCell {

    @IBOutlet private weak var nameLabel: UILabel!
    @IBOutlet private weak var positionLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    func setupCell(withContact contact: Contact) {
        nameLabel.text = contact.name
        positionLabel.text = contact.position
    }

}

С помощью добавления private к привычным нам IBOutlet можно гарантировать, что указанные поля ячейки не будет заданы из другого класса. Особенно это может быть полезно при командной работе, когда кто-то по неосторожности / нехватке времени / глупости (нужное подчеркнуть) попробует задать цвета, текст или какие-то другие свойства у Label-ов ячейки прямо в методе tableView(_:cellForRowAt:).

А представьте, что ячейка или целый ViewController содержит множество IBOutlet-ов, что настроек отображения масса. Не проще ли обезопасить себя добавлением private, чем потом искать почему внешний вид элемента вдруг изменился или откуда-то появился Gesture Recognizer, который задает неожиданное поведение?

P.S.: Если после прочтения вам захочется использовать private для IBOutlet-ов, то для простоты можно завести для этого снипет в Xcode.

Ниже приведен опрос, если вы захотите прокомментировать свой вариант ответа, welcome в комментарии.

Комментарии (10)


  1. GDXRepo
    30.09.2018 02:22
    -1

    Ой как много воды о том, что такое инкапсуляция (что аутлеты не должны торчать наружу)… И, кстати говоря, это зависит от применяемой архитектуры, иногда нужно как раз наоборот. Но если «по-простому» — то да, в большинстве случаев аутлеты, если уж вы их используете, делаем приватными, чтобы извне был доступен минимум информации. Все, вся статья в двух предложениях.


    1. slutsker Автор
      30.09.2018 08:57

      Во многих проектах, с которыми я сталкивался, аутлеты как раз «торчали наружу», помимо этого Xcode при создании аутлетов не предлагает быстро добавить private, поэтому я думаю, что пояснения будут не лишними, особенно для начинающих.

      image


  1. debug45
    30.09.2018 09:22
    +1

    В опросе нет вариантов без «private», но с «weak».


    1. slutsker Автор
      30.09.2018 09:37

      возможно, действительно имело смысл добавить еще несколько вариантов в том числе варианты без private — просто получалось очень массивно. а вы за вариант без private?


      1. debug45
        30.09.2018 09:42

        После прочтения Вашей статьи засомневался, но доселе использовал просто «weak var».


  1. eugeneego
    30.09.2018 10:14

    Также и weak не нужен, и местами даже опасен.


    1. slutsker Автор
      30.09.2018 10:15

      А можете рассказать поподробнее?


      1. eugeneego
        30.09.2018 10:22
        +1

        Типичная ситуация, захотел вдруг кодом изъять вьюшку, а потом вставить куда-либо снова.
        Разработчик пишет self.myView.removeFromSuperview(), и в этот момент вьюшка деаллоцируется, так ссылка держалась только иерархией вью, а не самим контроллером из-за weak, и далее так как у нас еще и IUO, то при обращунии без ? будет креш.
        Мало уже кто помнит, зачем давным давно писали weak в аутлетах ))).


  1. eugeneego
    30.09.2018 10:22

    -


  1. Stas_Telnov
    01.10.2018 12:07

    Я использую всегда (ну кроме отдельных случаев):

    @IBOutlet private var someLabel: UILabel?

    с тех пор, как начал писать на свифте.
    Про weak уже сказали выше — он не нужен.
    Но почему так много людей делают аутлеты не опшионалами?
    Ведь в теории, при передаче в контроллер какого-то параметра (из segue например и особенно когда они не приватны) аутлеты могут быть ещё не привязаны и не доступны?
    Что это? Авось и так прокатит?