Что такое необязательное значение в Swift?


person Tim Vermeulen    schedule 02.06.2014    source источник
comment
Связано: stackoverflow.com/questions / 24034483 /   -  person Bigood    schedule 23.06.2014
comment
Необязательно также можно рассматривать как реализацию монады Option / Maybe. Этот блог здесь хорошо помогает объяснить, что в противном случае является сложной концепцией.   -  person StuartLC    schedule 20.05.2015
comment
tldr: «Swift требует, чтобы вы четко понимали, когда значение может отсутствовать, а когда оно гарантированно существует». из отличного ответа ниже   -  person jonatan    schedule 25.06.2018


Ответы (13)


Необязательный параметр в Swift - это тип, который может содержать значение или не иметь значения. Необязательные параметры записываются путем добавления ? к любому типу:

var name: String? = "Bertie"

Опции (наряду с универсальными шаблонами) - одна из самых сложных для понимания концепций Swift. Из-за того, как они написаны и используются, легко получить неправильное представление о том, что они из себя представляют. Сравните приведенное выше необязательное действие с созданием обычной строки:

var name: String = "Bertie" // No "?" after String

Судя по синтаксису, необязательная строка очень похожа на обычную строку. Это не. Необязательная строка не является строкой с включенной необязательной настройкой. Это не особая разновидность String. Строка и необязательная строка - это совершенно разные типы.

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

Вы можете увидеть как реализованы опции в Стандартная библиотека Swift. Для этого введите «Необязательно» в любой файл Swift и щелкните по нему ⌘-щелчком. Вот важная часть определения:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Необязательный - это просто enum, который может быть одним из двух случаев: .none или .some. Если это .some, есть связанное значение, которое в приведенном выше примере будет String Hello. Необязательный параметр использует Generics для присвоения типа связанному значению. Тип необязательной строки - это не String, это Optional или, точнее, Optional<String>.

Все, что Swift делает с опциями, - это волшебство, делающее чтение и написание кода более плавным. К сожалению, это не позволяет понять, как это работает на самом деле. Я рассмотрю некоторые уловки позже.

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


Как создать опционалы

Чтобы создать необязательный, добавьте ? после типа, который вы хотите обернуть. Любой тип может быть необязательным, даже ваши собственные типы. Между типом и ? не может быть пробела.

var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)

// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}

Использование опционалов

Вы можете сравнить необязательный параметр с nil, чтобы узнать, есть ли у него значение:

var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
    print("There is a name")
}
if name == nil { // Could also use an "else"
    print("Name has no value")
}

Это немного сбивает с толку. Подразумевается, что необязательным является либо то, либо другое. Либо ноль, либо это Боб. Это неправда, необязательное не трансформируется во что-то другое. Сравнение его с nil - это уловка, позволяющая упростить чтение кода. Если необязательный параметр равен nil, это просто означает, что для перечисления в настоящее время установлено значение .none.


Только опции могут быть нулевыми

Если вы попытаетесь установить для необязательной переменной значение nil, вы получите сообщение об ошибке.

var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'

Другой способ рассматривать опциональные параметры - это дополнение к обычным переменным Swift. Они являются аналогом переменной, которая гарантированно имеет значение. Swift - осторожный язык, который ненавидит двусмысленность. Большинство переменных определены как необязательные, но иногда это невозможно. Например, представьте себе контроллер представления, который загружает изображение либо из кеша, либо из сети. Он может иметь или не иметь это изображение во время создания контроллера представления. Невозможно гарантировать значение переменной изображения. В этом случае вам придется сделать это необязательным. Он начинается с nil, и когда изображение извлекается, необязательный элемент получает значение.

Использование необязательного параметра раскрывает намерения программиста. По сравнению с Objective-C, где любой объект может быть нулевым, Swift требует, чтобы вы четко понимали, когда значение может отсутствовать, а когда оно гарантированно существует.


Чтобы использовать необязательный параметр, разверните его

Необязательный String не может использоваться вместо фактического String. Чтобы использовать обернутое значение внутри необязательного параметра, вы должны его развернуть. Самый простой способ развернуть необязательный элемент - добавить ! после имени необязательного элемента. Это называется принудительным разворачиванием. Он возвращает значение внутри необязательного (как исходный тип), но если необязательный параметр nil, это вызывает сбой во время выполнения. Перед разворачиванием убедитесь, что есть значение.

var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")

name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.

Проверка и использование необязательного

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

var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
    let unwrappedMealPreference: String = mealPreference!
    print("Meal: \(unwrappedMealPreference)") // or do something useful
}

В этом шаблоне вы проверяете наличие значения, а затем, когда вы уверены, что оно есть, вы принудительно разворачиваете его во временную константу для использования. Поскольку это обычное дело, Swift предлагает ярлык с использованием if let. Это называется необязательной привязкой.

var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
    print("Meal: \(unwrappedMealPreference)") 
}

Это создает временную константу (или переменную, если вы замените let на var), область действия которой находится только в фигурных скобках if. Поскольку необходимость использования таких имен, как unwrappedMealPreference или realMealPreference, является обузой, Swift позволяет повторно использовать исходное имя переменной, создавая временное имя в пределах области скобок.

var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // separate from the other mealPreference
}

Вот код, демонстрирующий, что используется другая переменная:

var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
    mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"

Необязательная привязка работает, проверяя, равно ли необязательное значение nil. В противном случае он разворачивает необязательный элемент в предоставленную константу и выполняет блок. В Xcode 8.3 и новее (Swift 3.1) попытка напечатать необязательный параметр, подобный этому, вызовет бесполезное предупреждение. Используйте необязательный debugDescription, чтобы заглушить его:

print("\(mealPreference.debugDescription)")

Для чего нужны опции?

Варианты имеют два варианта использования:

  1. Вещи, которые могут потерпеть неудачу (я чего-то ожидал, но ничего не получил)
  2. Вещи, которые сейчас ничто, но могут быть чем-то позже (и наоборот)

Несколько конкретных примеров:

  • Свойство, которое может быть там или не быть, например middleName или spouse в Person классе.
  • Метод, который может возвращать значение или ничего, например поиск совпадения в массиве.
  • Метод, который может вернуть либо результат, либо ошибку и ничего не вернуть, например, попытка прочитать содержимое файла (которое обычно возвращает данные файла), но файл не существует.
  • Свойства делегата, которые не всегда нужно устанавливать и обычно устанавливаются после инициализации
  • Для weak свойств в классах. То, на что они указывают, можно в любой момент установить на nil.
  • Большой ресурс, который, возможно, придется освободить, чтобы освободить память.
  • Когда вам нужен способ узнать, когда значение было установлено (данные еще не загружены ›данные), вместо использования отдельного файла dataLoaded Boolean

В Objective-C нет дополнительных опций, но есть эквивалентная концепция, возвращающая nil. Вместо этого методы, которые могут возвращать объект, могут возвращать nil. Это означает отсутствие действительного объекта и часто используется, чтобы сказать, что что-то пошло не так. Он работает только с объектами Objective-C, но не с примитивами или базовыми C-типами (перечисления, структуры). Objective-C часто имел специализированные типы для представления отсутствия этих значений (NSNotFound, что на самом деле NSIntegerMax, kCLLocationCoordinate2DInvalid для представления недопустимой координаты, -1 или некоторые отрицательные значения также используются). Кодировщик должен знать об этих особых значениях, поэтому они должны быть задокументированы и изучены для каждого случая. Если метод не может принимать nil в качестве параметра, это необходимо задокументировать. В Objective-C nil был указателем, так же как все объекты были определены как указатели, но nil указывал на конкретный (нулевой) адрес. В Swift nil - это литерал, который означает отсутствие определенного типа.


По сравнению с nil

Раньше вы могли использовать любой необязательный параметр в качестве Boolean:

let leatherTrim: CarExtras? = nil
if leatherTrim {
    price = price + 1000
}

В более поздних версиях Swift вы должны использовать leatherTrim != nil. Почему это? Проблема в том, что Boolean можно заключить в необязательный. Если у вас Boolean вот так:

var ambiguous: Boolean? = false

у него есть два вида ложных значений: в одном случае нет значения, а в другом есть значение, но значение равно false. Swift ненавидит двусмысленность, поэтому теперь вы всегда должны проверять необязательный параметр на nil.

Вы можете спросить, в чем смысл необязательного Boolean? Как и в случае с другими опциями, состояние .none может указывать на то, что значение пока неизвестно. На другом конце сетевого вызова может быть что-то, для опроса которого требуется некоторое время. Необязательные логические значения также называются трехзначными логическими значениями.


Быстрые трюки

Swift использует некоторые приемы, позволяющие работать с опциями. Рассмотрим эти три строки обычного необязательного кода;

var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }

Ни одна из этих строк не должна компилироваться.

  • Первая строка устанавливает необязательную строку с использованием литерала String, двух разных типов. Даже если бы это был String типы разные
  • Вторая строка устанавливает для необязательной String значение nil, два разных типа
  • Третья строка сравнивает необязательную строку с nil, два разных типа

Я рассмотрю некоторые детали реализации опций, которые позволяют этим строкам работать.


Создание необязательного

Использование ? для создания необязательного - это синтаксический сахар, разрешенный компилятором Swift. Если вы хотите сделать это долгим путем, вы можете создать необязательный параметр, например:

var name: Optional<String> = Optional("Bob")

Это вызывает первый инициализатор Optional, public init(_ some: Wrapped), который определяет связанный тип необязательного элемента из типа, используемого в круглых скобках.

Еще более длительный способ создания и установки необязательного:

var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")

Установка необязательного значения nil

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

var name: String?
var name: String? = nil

Разрешение дополнительных параметров равным nil разрешено протоколом ExpressibleByNilLiteral (ранее называвшимся NilLiteralConvertible). Необязательный параметр создается вторым инициализатором Optional, public init(nilLiteral: ()). В документации говорится, что вы не должны использовать ExpressibleByNilLiteral ни для чего, кроме дополнительных опций, поскольку это изменит значение nil в вашем коде, но это возможно:

class Clint: ExpressibleByNilLiteral {
    var name: String?
    required init(nilLiteral: ()) {
        name = "The Man with No Name"
    }
}

let clint: Clint = nil // Would normally give an error
print("\(clint.name)")

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

var name: Optional<String> = Optional(nilLiteral: ())

Сравнение необязательного с nil

Необязательные параметры определяют два специальных оператора == и! =, Которые вы можете увидеть в определении Optional. Первый == позволяет вам проверить, равен ли какой-либо необязательный параметр нулю. Два разных параметра, для которых установлено значение .none, всегда будут равны, если соответствующие типы одинаковы. Когда вы сравниваете с nil, за кулисами Swift создает необязательный параметр того же связанного типа, для которого установлено значение .none, а затем используется его для сравнения.

// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
    print("tuxedoRequired is nil")
}

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

Кроме того, он позволяет сравнивать любой тип Equatable с дополнительной оболочкой этого типа:

let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
    print("It's a match!") // Prints "It's a match!"
}

За кулисами Swift оборачивает необязательное как необязательное перед сравнением. Он также работает с литералами (if 23 == numberFromString {)

Я сказал, что есть два оператора ==, но на самом деле есть третий, который позволяет вам поместить nil в левую часть сравнения.

if nil == name { ... }

Варианты именования

Не существует соглашения Swift для наименования необязательных типов, отличных от необязательных типов. Люди избегают добавлять что-то к имени, чтобы показать, что это необязательный тип (например, optionalMiddleName или possibleNumberAsString), и позволяют объявлению показать, что это необязательный тип. Это становится трудным, когда вы хотите назвать что-то, что содержало бы значение из необязательного. Имя middleName подразумевает, что это тип String, поэтому, когда вы извлекаете из него значение String, вы часто можете получить такие имена, как actualMiddleName или unwrappedMiddleName или realMiddleName. Используйте необязательную привязку и повторно используйте имя переменной, чтобы обойти это.


Официальное определение

Из Основы языка программирования Swift:

Swift также вводит необязательные типы, которые обрабатывают отсутствие значения. Необязательные параметры говорят либо «есть значение, и оно равно x», либо «значения нет вообще». Необязательные параметры аналогичны использованию nil с указателями в Objective-C, но они работают для любого типа, а не только для классов. Опции более безопасны и выразительны, чем нулевые указатели в Objective-C, и лежат в основе многих самых мощных функций Swift.

Необязательные параметры - это пример того, что Swift - это типобезопасный язык. Swift помогает вам понять, с какими типами значений может работать ваш код. Если часть вашего кода ожидает String, безопасность типов не позволяет вам по ошибке передать ему Int. Это позволяет выявлять и исправлять ошибки как можно раньше в процессе разработки.


В заключение, вот стихотворение 1899 года о вариантах:

Вчера на лестнице
я встретила человека, которого там не было
Сегодня его не было здесь снова
Я бы хотел, чтобы он ушел
< br /> Антигонизм


Дополнительные ресурсы:

person nevan king    schedule 03.06.2014
comment
var myOtherString: String = Здравствуйте; если myOtherString {println (myOtherString)}; Выдает мне Тип "Строка" не соответствует протоколу "Логическое значение" - person Paul Brewczynski; 04.06.2014
comment
@bluesm Ты прав. Не уверен, откуда взялась эта другая ошибка. Сейчас отредактирую. - person nevan king; 04.06.2014
comment
Следуя вашему примеру, каким будет вывод var nameString: String? = nil, если nameString {println ((nameString) требует удовольствия от вашей компании)} else {println (Мы просим удовольствия от вашей компании)} - person Tash Pemhiwa; 05.06.2014
comment
Стив никогда не бывает необязательным! - person Kaan Dedeoglu; 22.07.2014
comment
@KaanDedeoglu К сожалению, Стив не обязателен. Он был здесь, а теперь его нет. - person nevan king; 22.07.2014
comment
if myString больше не компилируется. Вам нужно if myString != nil. См. документация. - person Pang; 05.08.2014
comment
привет, это тот же шаблон, что и шаблон "возможно", описанный в известном сообщении в блоге, в котором говорилось об ошибке нулевого указателя на миллиард долларов? - person pete; 10.09.2014
comment
лучшее и самое ясное объяснение? а также ! использование в Swift я нашел в Интернете. Спасибо - person mindbomb; 17.11.2014
comment
mateo подробно объясняет Возможности, углубляясь в простые примеры. - person iluvatar_GR; 11.12.2014
comment
Если я использую ! вместо ?, то я также получу тот же результат. Кто-нибудь может сказать разницу между использованием? а также / - person Henit Nathwani; 06.05.2015
comment
Спасибо за это объяснение, оно намного яснее, чем собственная документация Apple. - person yesthisisjoe; 24.12.2015
comment
if objectNotNil, как в Objective-C, - лучший способ безопасности. Я хочу, чтобы Optional тоже ушел, пусть компилятор скажет: эй, это небезопасно, пожалуйста, исправьте, как ... - person LE SANG; 05.04.2016
comment
Черт возьми, единственный туториал, который помог мне правильно понять опции. Блестящая работа мой друг @nevanking - person Siddharth; 12.10.2017
comment
Хорошая статья по этой теме: iosrock.blogspot. ru / 2018/09 / - person vivekDas; 28.09.2018
comment
Самый полный ответ на stackoverflow. Вы действительно король, мистер Неванский король. - person Massimo Polimeni; 24.01.2019
comment
Я все время вижу такой синтаксис: foo?.bar?.coollDude() в этой ситуации? сделать то же самое или что-то совершенно другое, чем приведенный выше ответ? - person Tim; 17.02.2019
comment
В разделе «Уловки Swift» (вар. Под Swift 5.0 (и, вероятно, раньше). Все они сейчас это делают, но на момент написания этой статьи (Swift 1.0?), Я полагаю, они не стали бы. Безусловно, лучшее описание Optional, которое я когда-либо читал. Спасибо. - person mswlogo; 20.04.2021

Давайте возьмем пример NSError, если не возвращается ошибка, вы хотите сделать необязательным возвращение Nil. Нет смысла присваивать ему значение, если нет ошибки.

var error: NSError? = nil

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

func doesntEnterNumber(x: Int? = 5) -> Bool {
    if (x == 5){
        return true
    } else {
        return false
    }
}
person John Riselvato    schedule 02.06.2014
comment
Предложение Если оно равно нулю, результат любого выражения с ним также будет нулем, просто неверно. func isNil<T>(t: T?) -> Bool { return t == nil } вернет true, даже если в выражении есть необязательное значение nil. - person return true; 24.04.2015
comment
Невероятно плохой образец кода. Не могли бы вы придумать что-нибудь получше? Почему не просто return x == 5? Что такого особенного в 5? - person Atomosk; 04.08.2016
comment
Нет, 2 года назад я не мог придумать ничего лучшего. Сегодня да, но понятно ли это? да. Спасибо за ввод @Atomosk, это действительно полезно. - person John Riselvato; 04.08.2016

У вас не может быть переменной, которая указывает на nil в Swift - нет указателей и нулевых указателей. Но в API вы часто хотите иметь возможность указать либо конкретный вид значения, либо отсутствие значения - например, есть ли у моего окна делегат, и если да, то кто это? Optionals - это безопасный для типов и памяти способ Swift сделать это.

person rickster    schedule 02.06.2014

Я сделал короткий ответ, который суммирует большую часть вышеизложенного, чтобы убрать неуверенность, которая была у меня в голове как новичка:

В отличие от Objective-C, никакая переменная не может содержать nil в Swift, поэтому был добавлен дополнительный тип переменной (переменные с суффиксом "?"):

    var aString = nil //error

Большая разница в том, что необязательные переменные не хранят значения напрямую (как обычные переменные Obj-C), они содержат два состояния: «имеет значение» или « имеет ноль ":

    var aString: String? = "Hello, World!"
    aString = nil //correct, now it contains the state "has nil"

Таким образом, вы можете проверить эти переменные в разных ситуациях:

if let myString = aString? {
     println(myString)
}
else { 
     println("It's nil") // this will print in our case
}

Используя знак "!" суффикс, вы также можете получить доступ к заключенным в них значениям, только если они существуют. (т.е. это не ноль):

let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!

println(anotherString) //it will print "Hello, World!"

Вот почему вам нужно использовать "?" а также "!" и не использовать их все по умолчанию. (это было мое самое большое недоумение)

Я также согласен с ответом выше: Необязательный тип не может использоваться как логическое.

person Teodor Ciuraru    schedule 24.12.2014

В объективном C переменные без значения были равны 'nil' (также можно было использовать 'nil' значения, такие же, как 0 и false), следовательно, можно было использовать переменные в условных операторах (переменные, имеющие значения, такие же, как 'TRUE 'и те, у которых нет значений, были равны' ЛОЖЬ ').

Swift обеспечивает безопасность типов, предоставляя «необязательное значение». т.е. предотвращает возникновение ошибок при присвоении переменных разного типа.

Таким образом, в Swift для условных операторов могут быть предоставлены только логические значения.

var hw = "Hello World"

Здесь, несмотря на то, что 'hw' является строкой, его нельзя использовать в операторе if, как в объекте C.

//This is an error

if hw

 {..}

Для этого его нужно создать как,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}
person Gokul    schedule 05.06.2014

Необязательное значение позволяет вам показать отсутствие значения. Немного похоже на NULL в SQL или NSNull в Objective-C. Думаю, это будет улучшением, поскольку вы можете использовать это даже для «примитивных» типов.

// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)”

Отрывок из: Apple Inc. «Быстрый язык программирования». iBooks. https://itun.es/gb/jEUH0.l

person Maria Zverina    schedule 02.06.2014
comment
nil - это просто синтаксический сахар для константы перечисления OptionalValue<T>.None (где T - это тип, соответствующий контексту, в котором вы используете nil). ? - это ярлык для OptionalValue<T>.Some(T). - person rickster; 03.06.2014

Необязательный параметр означает, что Swift не совсем уверен, соответствует ли значение типу: например, Int? означает, что Swift не совсем уверен, является ли число типом Int.

Чтобы удалить его, вы можете использовать три метода.

1) Если вы абсолютно уверены в типе, вы можете использовать восклицательный знак, чтобы принудительно развернуть его, например:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Если вы принудительно развернете необязательный параметр, и он равен нулю, вы можете столкнуться с этой ошибкой сбоя:

введите описание изображения здесь

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

Методы 2 и 3 защищают от этой проблемы.

2) Неявно развернутый необязательный

 if let unwrappedAge = age {

 // continue in here

 }

Обратите внимание, что теперь развернутый тип - Int, а не Int?.

3) Заявление охранника

 guard let unwrappedAge = age else { 
   // continue in here
 }

Отсюда вы можете продолжить и использовать развернутую переменную. Убедитесь, что развернули только принудительно (с помощью символа!), Если вы уверены в типе переменной.

Удачи тебе с твоим проектом!

person GJZ    schedule 30.10.2016

Когда я начал изучать Swift, было очень трудно понять, почему это необязательно.

Давайте так думать. Рассмотрим класс Person, у которого есть два свойства name и company.

class Person: NSObject {
    
    var name : String //Person must have a value so its no marked as optional
    var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible
    
    init(name:String,company:String?) {
        
        self.name = name
        self.companyName = company
        
    }
}

Теперь давайте создадим несколько объектов Person

var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil

Но мы не можем передать Nil в name

var personWithNoName:Person = Person.init(name: nil, company: nil)

Теперь давайте поговорим о том, почему мы используем optional?. Давайте рассмотрим ситуацию, когда мы хотим добавить Inc после названия компании, например, apple будет apple Inc. Нам нужно добавить Inc после названия компании и распечатать.

print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.

Теперь давайте изучим, почему необязательность имеет место.

if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
    
    print(companyString+" Inc") //Will never executed and no crash!!!
}

Заменим bob на tom

if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
    
    print(companyString+" Inc") //Will executed and no crash!!!
}

И Поздравляем! мы как следует разобрались с optional?

Итак, точки реализации

  1. Мы отметим переменную как необязательную, если она может быть nil
  2. Если мы хотим использовать эту переменную где-нибудь в коде, компилятор напомнит вам, что нам нужно проверить, правильно ли мы работаем с этой переменной, если она содержит nil.

Спасибо ... Удачного кодирования

person Tunvir Rahman Tusher    schedule 18.03.2017

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

var sampleString: String? ///Optional, Possible to be nil

sampleString = nil ////perfactly valid as its optional

sampleString = "some value"  //Will hold the value

if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.

    print(value+value)  ////Sample String merged into Two
}

sampleString = nil // value is nil and the

if let value = sampleString{

    print(value + value)  ///Will Not execute and safe for nil checking
}

//   print(sampleString! + sampleString!)  //this line Will crash as + operator can not add nil
person Tunvir Rahman Tusher    schedule 11.02.2017

Из https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html:

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

Чтобы понять глубже, прочтите ссылку выше.

person nizama bunti    schedule 12.07.2014

Хорошо...

? (Необязательно) указывает, что ваша переменная может содержать нулевое значение, а ! (unwrapper) указывает, что ваша переменная должна иметь память (или значение), когда она используется (пытается получить из нее значение) во время выполнения.

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

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

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

var defaultNil : Int?  // declared variable with default nil value
println(defaultNil) >> nil  

var canBeNil : Int? = 4
println(canBeNil) >> optional(4)

canBeNil = nil
println(canBeNil) >> nil

println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper

var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4

var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error

Вот подробное базовое руководство от комитета разработчиков Apple: Необязательная цепочка

person Krunal    schedule 02.06.2017

Необязательный параметр в Swift - это тип, который может содержать значение или не иметь значения. Необязательные параметры записываются добавлением ? к любому типу:

var name: String?

Вы можете обратиться к этой ссылке, чтобы получить более подробные сведения: https://medium.com/@agoiabeladeyemi/optionals-in-swift-2b141f12f870

person Vicky Prajapati    schedule 26.04.2019

Вот эквивалентное необязательное объявление в Swift:

var middleName: String?

Это объявление создает переменную с именем middleName типа String. Знак вопроса (?) После типа переменной String указывает, что переменная middleName может содержать значение, которое может быть либо String, либо nil. Любой, кто смотрит на этот код, сразу понимает, что middleName может иметь значение nil. Это самодокументируется!

Если вы не укажете начальное значение для необязательной константы или переменной (как показано выше), для вас автоматически будет установлено значение nil. Если вы предпочитаете, вы можете явно установить начальное значение на nil:

var middleName: String? = nil

для более подробной информации по желанию прочитайте ссылку ниже

http://www.iphonelife.com/blog/31369/swift-101-working-swifts-new-optional-values

person Devendra Agnihotri    schedule 09.01.2016
comment
используйте это, var middleName: String! знак равно - person Gaurav; 04.01.2017