[英]Why does Swift4 cast an array of UIButton! to [UIButton?] type?
今天遇到一個奇怪的問題。 請看這段代碼:
class A {
var button1: UIButton!
var button2: UIButton!
func foo() {
let array = [button1, button2]
}
}
Xcode 說該array
是[UIButton?]
類型。 出於某種原因,Swift4 強制轉換UIButton!
UIButton?
元素UIButton?
. 為什么?
解釋
ImplicitlyUnwrappedOptional
不是一個獨特的類型,而是一個帶有聲明其值的屬性的普通Optional
可能會被隱式強制(基於SE-0054 ):
然而,外觀! 在屬性或變量聲明的末尾不再表示該聲明具有 IUO 類型; 相反,它表明 (1) 聲明具有可選類型,以及 (2) 聲明具有一個屬性,表明其值可能是隱式強制的。 (沒有人會寫或觀察這個屬性,但我們將把它稱為@_autounwrapped。)這樣的聲明在下文中被稱為IUO 聲明。
因此,當您使用它時:
let array = [button1, button2]
編譯器將array
類型派生為[UIButton?]
,因為button1
和button2
的類型是Optional<UIButton>
,而不是ImplicitlyUnwrappedOptional<UIButton>
(即使只有一個按鈕是可選的,它也會派生出可選類型)。
在SE-0054 中了解更多信息。
邊注:
這種行為與arrays
並沒有真正的關系,在下面的例子中, button2
的類型將被派生到UIButton?
即使有!
並且在button
設置了一個值:
var button: UIButton! = UIButton()
func foo() {
let button2 = button // button2 will be an optional: UIButton?
}
解決方案
如果你想得到一個未包裝類型的數組,你有兩個選擇:
首先,正如Guy Kogus在他的回答中所建議的,使用顯式類型而不是讓 swift 派生它:
let array: [UIButton] = [button1, button2]
但是,如果有機會其中一個按鈕包含nil
,則會導致Unexpectedly found nil
崩潰。
雖然通過使用隱式解包的 optional 而不是可選( !
而不是?
),您聲稱這些按鈕中永遠不會有 nil,但我仍然更喜歡EmilioPelaez在他的評論中建議的第二個更安全的選項。 那就是使用flatMap
(Swift 4+ 中的compactMap
),它會過濾掉nil
s,如果有的話,並返回一個未包裝類型的數組:
let array = [button1, button2].flatMap { $0 }
因為UIButton!
不是一個類型,或者更確切地說它是一個UIButton?
有一些約定。 !
意味着總是隱式地解開可選項。 下列
var x: UIButton!
// Later
x.label = "foo"
語法糖是為了
var x: UIButton?
// Later
x!.label = "foo"
當您創建它們的數組時。 編譯器可以選擇隱式解包它們並推斷[UIButton]
或將它們保留為可選並推斷[UIButton?]
。 它選擇了兩個選項中更安全的選項。
Swift 通過假設它們是可選項來確保安全,而不是在默認情況下展開它們,因為它們在技術上可以是nil
。 如果您嘗試像這樣顯式地將它們標記為隱式解包
let array: [UIButton!] = [button1, button2]
您將收到以下錯誤:
錯誤:隱式解包的選項只允許在頂層和作為函數結果
在這種情況下,如果您希望它們被解開,那么只需將其定義為
let array: [UIButton] = [button1, button2]
我發現 Swift 博客確實是此類更改的最佳來源,因此:
在 Swift 4 之前:
許多人對隱式展開的可選項的心理模型是它們是一種類型,與常規可選項不同。 在 Swift 3 中,這正是它們的工作方式:像 var a: Int? 將導致具有類型 Optional 和類似 var b: String! 將導致 b 具有類型 ImplicitlyUnwrappedOptional。
斯威夫特 4
IUO 的新思維模型是您考慮的地方! 成為的同義詞? 另外,它在聲明上添加了一個標志,讓編譯器知道聲明的值可以隱式解包。
換句話說,您可以讀取 String! 因為“此值具有 Optional 類型,並且還帶有信息,說明它可以在需要時隱式解包”。
這種心理模型與新的實現相匹配。 任何有 T! 的地方,編譯器現在都將其視為具有類型 T? , 並在聲明的內部表示中添加一個標志,讓類型檢查器知道它可以在必要時隱式解包值。
全部引自Swift 博客
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.