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

267

Из документации Apple :

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

Почему вы хотите использовать необязательное значение?

Тим Вермейлен
источник
Связанный: stackoverflow.com/questions/24034483/…
Bigood
1
Необязательно также можно рассматривать как реализацию монады Option / Maybe . Этот блог делает хорошую работу, пытаясь объяснить, что в противном случае является сложной концепцией.
StuartLC
tldr: «Swift требует от вас четкого представления о том, когда значение может отсутствовать и когда оно гарантированно существует». из превосходного ответа
Невана Кинга

Ответы:

532

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

var name: String? = "Bertie"

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

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

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

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

Вы можете увидеть, как дополнительные функции реализованы в стандартной библиотеке Swift, введя «Optional» в любой файл 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 - это трюк, чтобы сделать код более простым для чтения. Если необязательный параметр равен нулю, это просто означает, что перечисление в настоящее время установлено на .none.


Только опционально может быть ноль

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

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

Другой способ взглянуть на опциональные возможности - это дополнение к обычным переменным 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 предлагает ярлык с использованием «если позволено». Это называется «необязательное связывание».

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

Это создает временную константу (или переменную , если заменить letс var), областью действия которого только в пределах , если это брекеты - х. Поскольку использование имени, такого как «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")"

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

print("\(mealPreference.debugDescription)")

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

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

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

Некоторые конкретные примеры:

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

Необязательные в Objective-C не существуют, но существует эквивалентная концепция, возвращающая ноль. Методы, которые могут вернуть объект, могут вернуть 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. Почему это? Проблема в том, что a Booleanможет быть обернут в необязательный. Если у вас есть Booleanтакие:

var ambiguous: Boolean? = false

у него есть два типа «ложь», один, где нет значения, и другой, где он имеет значение, но значение равно false. Свифт ненавидит двусмысленность, поэтому теперь вы всегда должны проверять опцию против nil.

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


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

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

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

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

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

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


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

Использование ?для создания необязательного синтаксического сахара, разрешено компилятором 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 для именования необязательных типов, отличных от необязательных типов. Люди избегают добавлять что-либо к имени, чтобы показать, что это необязательный параметр (например, «AdditionalMiddleName» или «возможный номер_строки»), и позволяют объявлению показать, что это необязательный тип. Это становится трудным, когда вы хотите назвать что-то для хранения значения из необязательного. Название «middleName» подразумевает, что это тип String, поэтому, когда вы извлекаете из него значение String, вы часто можете получить такие имена, как «actualMiddleName» или «unwrappedMiddleName» или «realMiddleName». Используйте необязательное связывание и повторно используйте имя переменной, чтобы обойти это.


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

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

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

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


Чтобы закончить, вот стихотворение 1899 года об опциях:

Вчера на лестнице
я встретил человека, которого там
не было. Сегодня его не было снова.
Мне бы хотелось, чтобы он ушел.

Антигонист


Больше ресурсов:

Неван Кинг
источник
5
@KaanDedeoglu К сожалению, Стив очень необязательный. Он был здесь, а теперь нет.
Неванский король
19
if myStringбольше не компилируется Вам нужно if myString != nil. Смотрите документацию .
Пан
5
лучшее и четкое объяснение? и ! использовать в Swift я нашел в Интернете. спасибо
mindbomb
2
Матео подробно объясняет Факультативы, глубже и простые примеры.
iluvatar_GR
4
Спасибо за это объяснение, оно намного понятнее, чем собственная документация Apple.
yesthisisjoe
16

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

var error: NSError? = nil

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

func doesntEnterNumber(x: Int? = 5) -> Bool {
    if (x == 5){
        return true
    } else {
        return false
    }
}
Джон Риселвато
источник
Предложение «Если это ноль, то результатом любого выражения с ним будет также ноль» просто неправильно. func isNil<T>(t: T?) -> Bool { return t == nil }вернется, trueдаже если nilв выражении есть необязательное значение .
вернуть истину
Невероятно плохой пример кода. Не могли бы вы придумать что-то лучше? Почему не просто return x == 5? Что такого особенного в 5?
Атомоск
Нет, 2 года назад я не мог придумать что-то лучшее. Сегодня да, но помогает ли это понять? да. Спасибо за ввод @ Atomosk, это действительно полезно.
Джон Риселвато
12

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

rickster
источник
11

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

В отличие от 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!"

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

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

Теодор Чурару
источник
7

В целевых 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

 {..}
Gokul
источник
5

Необязательное значение позволяет показать отсутствие значения. Немного похоже на 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. «Язык программирования Swift». интерактивные книги. https://itun.es/gb/jEUH0.l

Мария Зверина
источник
6
nilпросто синтаксический сахар для константы enum OptionalValue<T>.None(где Tтип соответствует контексту, в котором вы используете nil). ?это ярлык для OptionalValue<T>.Some(T).
Рикстер
4

Необязательный означает, что 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
 }

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

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

GJZ
источник
1

Когда я начал учиться, 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 never executed and no crash!!!
}

И поздравляю! мы имеем дело сoptional?

Таким образом, точки реализации

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

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

Тунвир Рахман Тушер
источник
0

Давайте поэкспериментируем с нижеследующим кодом 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
Тунвир Рахман Тушер
источник
0

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

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

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

Низама Бунти
источник
0

Хорошо...

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

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

Чтобы отразить тот факт, что необязательное сцепление может быть вызвано для значения nil, результатом необязательного вызова цепочки всегда является необязательное значение, даже если запрашиваемое свойство, метод или индекс, возвращают неопциональное значение. Это необязательное возвращаемое значение можно использовать, чтобы проверить, был ли необязательный вызов цепочки успешным (возвращаемая необязательная содержит значение) или не удалась из-за значения 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 Developer Committee: Необязательная цепочка

Krunal
источник
0

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

var name: String?

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

Вики Праджапати
источник
-1

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

var middleName: String?

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

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

var middleName: String? = nil

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

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

Девендра Агнихотри
источник
используйте это, var middleName: String! = ""
Гаурав