前言
在我們使用objective-c表示字符串信息的時候,可以用下面方法書寫。
NSString *str = @"秋恨雪"; str = nil;
因為objective-c是弱類型語言,所以這里的str既可以是具體的字符串也可以是nil。但到了Swift中就不可以了,因為Swift是類型安全的語言,一個String類型的變量不可能既能是具體的字符串,又可以為nil(更嚴格的說String類型的內容只能是字符串)。所以,在Swift中有了swift/81191.html">可選類型的概念。(其實這一概念也是“借鑒”于其他編程語言,比如C#,只不過在C#中稱之為可空類型)。
大家在初看Optionals的感覺很陌生,在我第一眼看到它的時候,我就在想...這是什么鬼...但是仔細想想的話,可選值Optionals類型的引入,為我們也帶了便利.
可選值(optionals)無可爭議的是 swift 語言中最重要的特性之一,也是和其他語言,例如 Objective-C 的最大區別。通過強制處理那些有可能出現 nil 的地方,我們就能寫出更有預測性的以及更健壯的代碼。
然而,有些時候可選值可能會致你于尷尬的境地,尤其是你作為開發者了解(甚至是有些猜測的成分在),有的特定變量始終是非空(non-nil)的,即使它是一個可選類型。例如,我們在一個視圖控制器中處理視圖的時候:
class TableViewController: UIViewController { var tableView: UITableView? override func viewDidLoad() { super.viewDidLoad() tableView = UITableView(frame: view.bounds) view.addSubview(tableView!) } func viewModelDidUpdate(_ viewModel: ViewModel) { tableView?.reloadData() }}
這也是對于很多 Swift 程序員爭論比較激烈的地方,程度不亞于討論 tabs 和 spaces 的用法。有的人會說:
既然它是一個可選值,你就應該時刻使用 if let 或者 guard let 的方式進行解包。
然而另外一些人則采用完全相反,說:
既然你知道這個變量在使用的時候不會為 nil,使用 ! 強制解包多好。崩潰也要比讓你的程序處于一個未知狀態要好吧。
本質上來講,我們這里討論的是要不要采用防御性編程(defensive programming)的問題。我們是試圖讓程序從一個未知狀態恢復還是簡單的放棄,然后讓它崩潰掉?
如果非得讓我對這個問題給出一個答案的話,我更傾向于后者。未知狀態真的很難追蹤 bug,會導致執行很多不想執行的邏輯,采用防御性編程就會使得你的代碼很難追蹤,出現問題很難追蹤。
但是,我不太喜歡給出一個二選一的答案。相反,我們可以尋找一些技術手法,用更精妙的方式的解決上面提到的問題。
它真的可選的嗎?
那些可選類型的,但是被代碼邏輯真實需要的變量和屬性,實際上是架構瑕疵的一個體現。如果在某些地方確實需要它,但是它又不在,就會使得你的代碼邏輯處于未知狀態,那么它就不應該是可選類型的。
當然,在某些特定場景下,可選值確實很難避免(尤其是和特定的系統 API 交互的時候),那對于大部分這種情況,我們有一些技術來處理從而避免可選值。
lazy 要比非可選的可選值更好
某些屬性的值需要在其父類創建之后再生成(比如視圖控制器中的那些視圖,應該在 loadView()或者 viewDidLoad()方法中被創建),對于這種屬性要避免其可選類型的方法就是使用 lazy 屬性。一個lazy屬性是可以是非可選類型的,同時也不在其父類的初始化方法里被需要,它會在其第一次被獲取的時候創建出來。
讓我們改一下上面的代碼,使用 lazy 來改造 tableView 屬性:
class TableViewController: UIViewController { lazy var tableView = UITableView() override func viewDidLoad() { super.viewDidLoad() tableView.frame = view.bounds view.addSubview(tableView) } func viewModelDidUpdate(_ viewModel: ViewModel) { tableView.reloadData() }}
這樣,沒有可選值了,也不會有未知狀態咯
注:相關教程知識閱讀請移步到swift教程頻道。
新聞熱點
疑難解答