2015-06-28 4 views
11

я только начал изучать Свифта и недавно узнал оКогда использовать?,!, None или Lazy?

  1. "Нормальные" переменные (за неимением лучшего названия):

    например: var test1: String

  2. "Дополнительно" переменные

    ex: var test2: String?

  3. "Косвенно Незавернутые Optionals"

    например: var test3: String!

  4. Ленивые переменные

    например: lazy var test4: String

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

  1. Использование «Дополнительно» переменные (?), Когда переменная может или не может быть инициализирован в точках в будущем, начиная с инициализации

  2. Использование «Косвенно Незавернутые Optionals» (!), Когда переменная гарантированно будет инициализирован

  3. Optionals могут быть преобразованы в неявном распакованных OPTIONALS с помощью «Принудительный Unwrapping»

    например: let possibleString: String? = "Hello" println(possibleString!)

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

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

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

  2. Когда я использую «ленивый»

  3. Я читал «ленивым» часто используется для singletons - почему?

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

Edit: Вот все, что я нашел (Основной вопрос был "Normal" против "имплицитно распакованных OPTIONALS":

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

ответ

2

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

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

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

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

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

+0

Ah okay, когда я буду использовать var test1: String // без? и нет ! ? – AeonNeo

+1

Вы бы написали несколько тысяч строк кода Swift и в конце концов выяснили это. – gnasher729

+1

@AeonNeo, это зависит от вашего дизайна. Если значение «нет значения» для свойства является частью потока, используйте «?». Если он почти всегда будет иметь значение, кроме некоторых «особых» периодов, когда он не будет, но в течение этих периодов он не будет доступен, используйте «!». В противном случае придерживаться «нормального» свойства. И вообще, если вы можете пойти без использования опций, идите без них. Иногда они могут быть довольно сложными (особенно неявно разворачиваемые). – courteouselk

1

Давайте посмотрим пример компании Apple

class Person { 
    var residence: Residence? 
} 

class Residence { 
    var numberOfRooms = 1 
} 

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

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

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

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

ПРИМЕЧАНИЕ

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

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

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

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

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

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

+0

Когда у меня есть этот код: класс Car { вар пассажиры: Int Init() { // passengers = 1 } Это не скомпилируется, потому что в нем говорится, что не все инициализировано, разве это не означает, что он не вставляет значение по умолчанию? – AeonNeo

+0

согласился, я отредактирую ответ. я посмотрел на документацию, вы должны инициализировать var, когда используете его без? а также ! – Doro

+0

@Доро, ладно. В таком случае, не надо! и не используя что-либо в конце, в принципе имеют ту же функцию? – AeonNeo

0

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

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

var a : String 
var b = "bar" 

init { 
    a = "foo" 
} 

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

var a : String! 

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

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

var a : String? // = nil 

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

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

В этом случае, какова польза (если таковая имеется) с помощью уаг A: String в отличие от вар в: String! , учитывая, что оба они должны быть инициализированы в строке инициализации/строке декларации/той же области видимости? – AeonNeo

+0

'var a: String!' Не должно быть инициализировано в строке метода init/declaration. Я изменил сообщение, чтобы уточнить – vadian

+0

Хм, я могу скомпилировать/запустить: var a: String! = "это строка" , так что он может быть инициализирован – AeonNeo

Смежные вопросы