簡體   English   中英

為什么 Swift4 會投射一個 UIButton 數組! [UIButton?] 類型?

[英]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?] ,因為button1button2的類型是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM