Когда использовать?,!, None или Lazy?

Я только начал изучать Свифт и недавно узнал о

  • "Нормальные" переменные (из-за отсутствия лучшего имени):

    ex: var test1: String

  • "Необязательные" переменные

    ex: var test2: String?

  • "Неявно отключенные опции"

    ex: var test3: String!

  • Ленивые переменные

    ex: lazy var test4: String

Мое понимание таково:

  • Используйте "Необязательные" переменные (?), когда переменная может быть инициализирована или не может быть инициализирована в будущих периодах, начиная с инициализации

  • Используйте "Неявно отключенные опции" (!), когда переменная гарантирована для инициализации

  • Опционы могут быть преобразованы в Implicitly Unwrapped Optionsals через "Принудительная развязка"

    ex: let possibleString: String? = "Hello" println(possibleString!)

  • Используйте "ленивые переменные" , когда нет необходимости в том, чтобы что-то было установлено до инициализации (кажется, они могут использоваться с (?) или (!))

Поэтому мои вопросы:

  • Когда я использую параметр 1 - переменную без? и без!

  • Когда я использую "ленивый"

  • Я читал "ленивый", который часто используется для синглтонов - почему?

У меня больше всего опыта в Java и С++, если это помогает с моим фоном для ответа.

Изменить: Здесь все, что я нашел (Основная проблема: "Нормальный" vs "Неявно отключенные опции" :

  • "Нормальные" переменные должны быть инициализированы: (a) В той же строке (b) в той же области до использования (использование означает некоторую операцию с объектом), (c) end от init iff переменная является полем. Примечание: область действия init - это все, что входит в класс класса И не входит в объем функций внутри класса.
  • Печать Неявно Unwrapped Необязательный будет печатать "nil", но использование переменных функций приведет к исключению среды выполнения. Между тем, используя (вообще, включая печать) переменную Обычный не позволит программе компилироваться вообще
  • Цель использования! over "" (Nothing): (a) Большая снисходительность, так как программа будет компилироваться (и выполняется корректно, если переменная фактически инициализирована) и (b) Позволяет вам не инициализировать все в самом начале. Примечание. Это ошибка времени компиляции, чтобы иметь необработанное поле, если оно является переменной Обычный.

Ответ 1

Не совсем так.

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

Неявно развернутые опции - это своего рода сокращение для случаев, когда переменная может быть пустой, но мы абсолютно уверены, что, когда мы будем ее использовать, она будет иметь фактическое значение (типичный пример - свойство в контроллере представления, ссылается на представление).

Принудительная развертка не конвертирует необязательный в неявно разворачиваемый необязательный вариант, вместо этого он дает вам значение, которое там, если оно есть (то есть, если необязательно, не nil), и генерирует исключение, если оно не является.

Ленивые свойства используются в тех случаях, когда вы хотите отложить их инициализацию на более поздний этап, когда свойство фактически используется в первый раз. Обычный случай - если вам нужно получить доступ к дорогому ресурсу, чтобы сделать это (загрузите огромный файл с диска, загрузите его через сеть и т.д.), Тем более, если могут быть случаи, когда такое свойство вообще не будет использоваться (почему загрузка это с диска, если мы не будем использовать его, вероятно?).

Ответ 2

см. пример Apple

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

У экземпляров резиденции есть одно свойство Int, называемое numberOfRooms, со значением по умолчанию 1. У экземпляров экземпляра есть необязательное свойство проживания типа Residence?.

Если вы создаете новый экземпляр Person, его свойство проживания по умолчанию инициализируется нулем, в силу необязательности.

1. Если вам нужно значение по умолчанию для свойства , которое должно быть nil - используйте необязательный. Использовать переменную без? а также! - как "numberOfRooms" -

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

Примечание

Если свойство всегда принимает одно и то же начальное значение, укажите значение по умолчанию вместо установки значения в инициализаторе. Конец результат тот же, но значение по умолчанию связывает свойства более тесная инициализация его декларации. Это сокращает, более ясные инициализаторы и позволяет вам вывести тип имущества от значения по умолчанию. Значение по умолчанию также облегчает вам чтобы использовать инициализаторы по умолчанию и наследование инициализатора.

2. ! используется для доступа к переменной, обернутой внутри переменной, когда она не равна нулю, и выбрасывает исключение в противном случае. Итак, вы можете использовать! чтобы сделать отметку для пользователей вашего класса - "это значение не будет равно нулю в момент его разворачивания"

3. Lazy variable используется, когда вы хотите ее запустить позже, а не во время создания всего объекта, но точно в то время, когда вы запрашиваете getter для данных. это полезно, когда свойство хранит массив, например:

lazy var players: [String] = {
        var temporaryPlayers = [String]()
        temporaryPlayers.append("John Doe")
        return temporaryPlayers
        }()

Когда следует использовать ленивую инициализацию?

Один пример использования ленивой инициализации - это когда начальное значение свойства неизвестно до тех пор, пока объект не будет инициализирован.

Ответ 3

Краткое объяснение:

A необязательная переменная всегда имеет значение и никогда не может быть равна нулю. Переменная должна быть инициализирована в методе init или в строке объявления.

var a : String
var b = "bar"

init {
    a = "foo"
}

В методе init может быть инициализирована неявная развернутая необязательная переменная не или в строке объявления, но гарантированно будет всегда иметь значение, когда он использует

var a : String!

func viewDidLoad() {
    a = "Hello"
    a += " world!"
}

необязательная переменная может иметь значение и равна нулю при объявлении

var a : String?  // = nil

A ленивая переменная инициализируется позже в тот момент, когда она использовалась в первый раз

class foo {
  lazy var bar : String = {
    return "Hello"
    }()
}