Swift'te isteğe bağlı bir değer ya da değeri olmayan bir türdür. Opsiyoneller, ?
herhangi bir türe a eklenerek yazılır :
var name: String? = "Bertie"
Seçenekler (Generics ile birlikte) anlaşılması en zor Swift kavramlarından biridir. Nasıl yazıldıklarından ve kullanıldıklarından dolayı, ne oldukları hakkında yanlış bir fikir edinmek kolaydır. Yukarıdaki isteğe bağlı olanı normal bir String oluşturmakla karşılaştırın:
var name: String = "Bertie" // No "?" after String
Sözdiziminden, isteğe bağlı bir Dize, sıradan bir Dize'ye çok benziyor gibi görünüyor. Değil. İsteğe bağlı bir Dize, bazı "isteğe bağlı" ayarların açık olduğu bir Dize değildir. Özel bir String türü değildir. Bir Dize ve isteğe bağlı bir Dize tamamen farklı türlerdir.
İşte bilinmesi gereken en önemli şey: İsteğe bağlı bir tür kaptır. İsteğe bağlı bir Dize, bir Dize içerebilecek bir kaptır. İsteğe bağlı Int, Int içeren bir kaptır. İsteğe bağlı bir tür parsel düşünün. Açmadan önce (veya seçeneklerin dilinde "paketini aç"), bir şey içerip içermediğini bilemezsiniz.
Herhangi bir Swift dosyasına "İsteğe Bağlı" yazıp ⌘ üzerine tıklayarak seçeneklerin Swift Standart Kitaplığında nasıl uygulandığını görebilirsiniz . İşte tanımın önemli kısmı:
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
İsteğe bağlı, enum
iki durumdan biri olabilen yalnızca bir tanesidir: .none
veya .some
. Eğer öyleyse .some
, yukarıdaki örnekte String
"Merhaba" olacak ilişkili bir değer vardır . Bir isteğe bağlı, ilişkili değere bir tür vermek için Generics kullanır. İsteğe bağlı bir Dize türü değil String
, Optional
daha doğrusu Optional<String>
.
Swift'in opsiyonellerle yaptığı her şey, okuma ve yazma kodunu daha akıcı hale getirmek için sihirdir. Ne yazık ki bu aslında çalışma şeklini gizliyor. Daha sonra bazı hilelerden geçeceğim.
Not: İsteğe bağlı değişkenler hakkında çok konuşacağım, ancak isteğe bağlı sabitler oluşturmak da iyidir. Oluşturulan tür türlerini daha kolay anlamak için tüm değişkenleri türleriyle işaretliyorum, ancak kendi kodunuzda olmak zorunda değilsiniz.
Optionals nasıl oluşturulur
İsteğe bağlı oluşturmak için, ?
sarmak istediğiniz türden sonra a ekleyin . Herhangi bir tür isteğe bağlı olabilir, hatta kendi özel türleriniz bile. Tür ile ?
. Arasında boşluk olamaz .
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
}
Opsiyonelleri kullanma
nil
Bir değeri olup olmadığını görmek için isteğe bağlı olanı karşılaştırabilirsiniz :
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")
}
Bu biraz kafa karıştırıcı. Bu isteğe bağlı bir şey ya da başka bir şey anlamına gelir. Nil ya da "Bob". Bu doğru değil, isteğe bağlı başka bir şeye dönüşmez. Bunu nil ile karşılaştırmak, okunması kolay kod yapmak için bir numaradır. İsteğe bağlı nil değerine eşitse, bu yalnızca sıralamanın şu anda ayarlı olduğu anlamına gelir .none
.
Yalnızca isteğe bağlı seçenekler boş olabilir
İsteğe bağlı olmayan bir değişkeni nil olarak ayarlamaya çalışırsanız bir hata alırsınız.
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
Opsiyonellere bakmanın bir başka yolu, normal Swift değişkenlerini tamamlayıcıdır. Bunlar, bir değere sahip olacağı garanti edilen bir değişkenin karşılığıdır. Swift, belirsizlikten nefret eden dikkatli bir dildir. Değişkenlerin çoğu isteğe bağlı olmayan olarak tanımlanır, ancak bazen bu mümkün değildir. Örneğin, bir görüntüyü önbellekten veya ağdan yükleyen bir görünüm denetleyicisi düşünün. Görüntü denetleyicisinin oluşturulduğu sırada bu görüntüye sahip olabilir veya olmayabilir. Görüntü değişkeni değerini garanti etmenin bir yolu yoktur. Bu durumda, isteğe bağlı yapmanız gerekir. nil
Görüntü alındığında başlar ve isteğe bağlı olarak bir değer elde edilir.
İsteğe bağlı bir program kullanılması programcıların amacını ortaya çıkarır. Herhangi bir nesnenin sıfır olabileceği Objective-C ile karşılaştırıldığında, Swift bir değerin ne zaman eksik olabileceği ve varlığının ne zaman garanti edileceği konusunda net olmanızı gerektirir.
İsteğe bağlı kullanmak için, "paketini açar"
İsteğe bağlı String
bir gerçek yerine kullanılamaz String
. Sarılmış değeri isteğe bağlı olarak kullanmak için, değerinin paketini açmanız gerekir. Bir isteğe bağlı paketini açmanın en basit yolu !
, isteğe bağlı adın sonuna bir etiket eklemektir . Buna "kuvvet açma" denir. İsteğe bağlı (orijinal tür olarak) içindeki değeri döndürür, ancak isteğe bağlı ise nil
bir çalışma zamanı çökmesine neden olur. Paketini açmadan önce bir değer olduğundan emin olmalısınız.
var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")
name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.
İsteğe bağlı kontrol ve kullanma
Paketini açmadan ve isteğe bağlı kullanmadan önce nil'i her zaman kontrol etmeniz gerektiğinden, bu yaygın bir kalıptır:
var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
let unwrappedMealPreference: String = mealPreference!
print("Meal: \(unwrappedMealPreference)") // or do something useful
}
Bu modelde bir değerin var olup olmadığını kontrol edersiniz, o zaman emin olduğunuzda, onu açmak için geçici bir sabit haline getirmeye zorlarsınız. Bu çok yaygın bir şey olduğu için Swift, "izin ver" i kullanarak bir kısayol sunuyor. Buna "isteğe bağlı bağlama" denir.
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
print("Meal: \(unwrappedMealPreference)")
}
Bu geçici bir sabit (veya değişken değiştirmek eğer yaratır let
ile var
olan kapsamı yalnızca en parantez içindedir). "UnwrappedMealPreference" veya "realMealPreference" gibi bir ad kullanmak zorunda kalmak bir yük olduğundan, Swift, orijinal değişken adını yeniden kullanmanıza izin verir ve parantez kapsamı içinde geçici bir ad oluşturur
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // separate from the other mealPreference
}
Farklı bir değişkenin kullanıldığını gösteren bazı kodlar şunlardır:
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")"
İsteğe bağlı ciltleme, isteğe bağlı olarak nil olup olmadığını kontrol ederek çalışır. Değilse, isteğe bağlı olanı sağlanan sabitin içine açar ve bloğu yürütür. Xcode 8.3 ve sonraki sürümlerde (Swift 3.1), böyle bir isteğe bağlı yazdırmaya çalışmak işe yaramaz bir uyarıya neden olacaktır. Susturmak için isteğe bağlı debugDescription
olanları kullanın :
print("\(mealPreference.debugDescription)")
Seçenekler nelerdir?
Opsiyonellerin iki kullanım durumu vardır:
- Başarısız olabilecek şeyler (bir şey bekliyordum ama hiçbir şeyim yoktu)
- Şimdi hiçbir şey olmayan ama daha sonra bir şey olabilir (ve tersi)
Bazı somut örnekler:
- Orada orada olur muyum olmaz gibi olabilir Bir özellik
middleName
veya spouse
bir bölgesi Person
sınıfta
- Bir dizide eşleşme aramak gibi bir değer veya hiçbir şey döndüremeyen bir yöntem
- Bir dosyanın içeriğini (normalde dosyanın verilerini döndürür) okumaya çalışmak gibi bir sonuç döndüren veya hata alıp hiçbir şey döndürmeyen bir yöntemdir, ancak dosya mevcut değildir
- Her zaman ayarlanması gerekmeyen ve genellikle başlatma işleminden sonra ayarlanan temsilci özellikleri
- İçin
weak
sınıflarında özellikleri. İşaret ettikleri şey nil
her zaman ayarlanabilir
- Belleği geri kazanmak için serbest bırakılması gerekebilecek büyük bir kaynak
- Ayrı bir veri kullanmak yerine bir değerin ne zaman ayarlandığını (henüz yüklenmemiş veriler> veriler) bilmenin bir yoluna ihtiyacınız olduğunda
Boolean
Objective-C'de seçenekler mevcut değildir, ancak sıfır döndüren eşdeğer bir kavram vardır. Bir nesneyi döndürebilen yöntemler bunun yerine nil döndürebilir. Bu, "geçerli bir nesnenin yokluğu" anlamına gelir ve genellikle bir şeylerin yanlış gittiğini söylemek için kullanılır. Yalnızca Objective-C nesneleriyle çalışır, ilkellerle veya temel C türleriyle (numaralandırmalar, yapılar) çalışmaz. Amaç-Cı genellikle bu değerlerin olmadığını temsil çeşitlerini uzman vardı ( NSNotFound
gerçekten NSIntegerMax
, kCLLocationCoordinate2DInvalid
bir koordinat değeri geçersiz temsil etmek, -1
ya da negatif değeri de kullanılır). Kodlayıcının bu özel değerleri bilmesi gerekir, böylece her vaka için belgelenmeli ve öğrenilmelidir. Bir yöntem alınamıyorsanil
parametre olarak , bunun belgelenmesi gerekir. Objective-C'de,nil
tıpkı tüm nesnelerin işaretçi olarak tanımlandığı, ancak nil
belirli (sıfır) bir adrese işaret ettiği gibi bir göstericiydi . Swift'te, nil
belirli bir türün olmaması anlamına gelen bir değişmezdir.
İle karşılaştırıldığında nil
Eskiden herhangi bir isteğe bağlı olarak aşağıdakileri kullanabilirsiniz Boolean
:
let leatherTrim: CarExtras? = nil
if leatherTrim {
price = price + 1000
}
Swift'in daha yeni sürümlerinde kullanmanız gerekir leatherTrim != nil
. Bu neden? Sorun şu ki, a Boolean
isteğe bağlı olarak sarılabilir. Eğer böyle bir şey varsa Boolean
:
var ambiguous: Boolean? = false
iki tür "yanlış" vardır, biri değerin olmadığı, diğeri değerin olduğu ancak değerin olduğu false
. Swift belirsizlikten nefret eder, bu yüzden şimdi her zaman isteğe bağlı olarak kontrol etmelisiniz nil
.
Bir isteğe bağlı amacının ne olduğunu merak edebilirsiniz Boolean
? Diğer seçeneklerde olduğu gibi, .none
durum değerin henüz bilinmediğini gösterebilir. Bir şebeke çağrısının diğer ucunda anket yapmak biraz zaman alabilir. Opsiyonel Boolelara " Üç Değerli Boolelar " da denir
Hızlı hileler
Swift, seçeneklerin çalışmasına izin vermek için bazı hileler kullanır. Sıradan görünümlü isteğe bağlı kodun bu üç satırını düşünün;
var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
Bu satırların hiçbiri derlenmemelidir.
- İlk satır, iki farklı tür olan bir String dizesi kullanarak isteğe bağlı bir String ayarlar. Bu bir
String
tür bile olsa farklı
- İkinci satır isteğe bağlı bir String'i nil, iki farklı tip olarak ayarlar
- Üçüncü satır, isteğe bağlı bir dizeyi nil, iki farklı türle karşılaştırır
Bu satırların çalışmasına izin veren seçeneklerin bazı uygulama ayrıntılarını inceleyeceğim.
İsteğe bağlı oluşturma
?
Swift derleyici tarafından etkinleştirilen, sözdizimsel bir şeker oluşturmak için kullanmak . Bunu uzun bir yoldan yapmak istiyorsanız, böyle bir isteğe bağlı oluşturabilirsiniz:
var name: Optional<String> = Optional("Bob")
Bu , isteğe bağlı olan ilişkili türü parantez içinde kullanılan türden ihlal eden Optional
ilk başlatıcısıdır public init(_ some: Wrapped)
.
İsteğe bağlı bir oluşturma ve ayarlama işleminin daha da uzun yolu:
var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
İçin isteğe bağlı nil
Başlangıç değeri olmayan bir isteğe bağlı oluşturabilir veya başlangıç değeri olan bir tane oluşturabilirsiniz nil
(her ikisinin de aynı sonucu vardır).
var name: String?
var name: String? = nil
Seçeneklerin eşit olmasına izin vermek nil
protokol tarafından etkinleştirilir ExpressibleByNilLiteral
(önceden adlandırılmıştı NilLiteralConvertible
). İsteğe bağlı, Optional
'ın ikinci başlatıcısı ile oluşturulur public init(nilLiteral: ())
. Dokümanlar ExpressibleByNilLiteral
, seçenekleriniz dışında hiçbir şey için kullanmamanız gerektiğini söylüyor , çünkü bu, kodunuzdaki nil'in anlamını değiştirecek, ancak bunu yapmak mümkün:
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)")
Aynı protokol önceden oluşturulmuş bir isteğe bağlı olarak ayarlamanızı sağlar nil
. Tavsiye edilmemesine rağmen, nil hazır bilgi başlatıcısını doğrudan kullanabilirsiniz:
var name: Optional<String> = Optional(nilLiteral: ())
İsteğe bağlı ile karşılaştırılması nil
İsteğe bağlı olarak, Optional
tanımda görebileceğiniz iki özel "==" ve "! =" Operatörü tanımlanır. Birincisi ==
, isteğe bağlı olanların nil'e eşit olup olmadığını kontrol etmenizi sağlar. İlişkili türler aynıysa, .none olarak ayarlanan iki farklı seçenek her zaman eşit olacaktır. Nil ile karşılaştırdığınızda, sahne arkasında Swift aynı .none olarak ayarlanmış aynı türden bir isteğe bağlı oluşturur, daha sonra bunu karşılaştırma için kullanır.
// 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")
}
İkinci ==
operatör iki seçeneği karşılaştırmanıza izin verir. Her ikisinin de aynı tür olması ve bu türün uyumlu olması gerekir Equatable
(normal "==" operatörüyle işleri karşılaştırmaya izin veren protokol). Swift (muhtemelen) iki değeri açar ve doğrudan karşılaştırır. Ayrıca seçeneklerden birinin veya her ikisinin olduğu durumu da ele alır .none
. nil
Değişmez değerle karşılaştırma arasındaki farkı not edin .
Ayrıca, herhangi bir Equatable
türü bu tür isteğe bağlı bir ambalajla karşılaştırmanıza olanak tanır :
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
print("It's a match!") // Prints "It's a match!"
}
Sahne arkasında, Swift isteğe bağlı olmayan isteğe bağlı olarak karşılaştırma önce sarar. Değişmez değerlerle de çalışır ( if 23 == numberFromString {
)
İki ==
operatör olduğunu söyledim , ama aslında nil
karşılaştırmanın sol tarafına koymanıza izin veren bir üçüncü
if nil == name { ... }
Adlandırma Seçenekleri
İsteğe bağlı türleri isteğe bağlı olmayan türlerden farklı olarak adlandırmak için Swift kuralı yoktur. Kullanıcılar, adın isteğe bağlı olduğunu ("isteğe bağlıMiddleName" veya "possibleNumberAsString" gibi) göstermek için bir şey eklemekten kaçınır ve bildirimin isteğe bağlı bir tür olduğunu göstermesine izin verir. İsteğe bağlı bir değeri tutmak için bir şey adlandırmak istediğinizde bu zorlaşır. "MiddleName" adı, bunun bir String türü olduğunu ima eder; bu nedenle, String değerini bundan aldığınızda, genellikle "actualMiddleName" veya "unwrappedMiddleName" veya "realMiddleName" gibi adlarla karşılaşabilirsiniz. İsteğe bağlı ciltleme kullanın ve bu sorunu aşmak için değişken adını yeniden kullanın.
Resmi tanım
itibaren Swift Programlama Dili "Temel" :
Swift ayrıca bir değerin yokluğunu işleyen isteğe bağlı türleri de sunar. Opsiyoneller ya “bir değer vardır ve x'e eşittir” ya da “hiç bir değer yoktur” der. Opsiyoneller, Objective-C'de işaretçilerle nil kullanmaya benzer, ancak sadece sınıflar için değil, her tür için çalışırlar. Opsiyoneller Objective-C'deki sıfır işaretçilerden daha güvenli ve daha etkileyici ve Swift'in en güçlü özelliklerinin çoğunun kalbinde yer alıyor.
Opsiyoneller, Swift'in güvenli bir dil olduğu gerçeğine bir örnektir. Swift, kodunuzun çalışabileceği değer türleri hakkında net olmanıza yardımcı olur. Kodunuzun bir kısmı bir Dize bekliyorsa, security yazdığınızda kodu yanlışlıkla Int olarak iletmeniz engellenir. Bu, geliştirme sürecinde hataları mümkün olduğunca erken yakalamanızı ve düzeltmenizi sağlar.
Bitirmek için, 1899'dan opsiyonellerle ilgili bir şiir:
Dün merdivende
orada olmayan bir adamla tanıştım
Bugün tekrar orada değildi
Keşke, keşke
Antigonca
Daha fazla kaynak: