2014-09-01 40 views
3

如果某個函數返回隱式解包的可選項,是否將其分配給明確的可選項?將隱含解包的可選項分配給明確的可選

例如,在Chris Adamson的blog post中,他首先列出了一個返回隱式解開的函數,後來他將該函數的返回值賦給了一個顯式的可選項。

class func JSONObjectWithData(_ data: NSData!, 
         options opt: NSJSONReadingOptions, 
         error error: NSErrorPointer) -> AnyObject! 

let jsonResponse : AnyObject? = 
NSJSONSerialization.JSONObjectWithData(evilData, 
    options: NSJSONReadingOptions(0), 
    error: &parseError); 

如果函數要返回不能爲零的東西,爲什麼要將它分配給可選項?

+0

在當前(測試版6 )SDK,JSONObjectWithData()返回'AnyObject?'。 – 2014-09-01 16:42:43

+0

感謝馬丁R,我意識到這一點 - 想用克里斯的例子來找出他爲什麼指派一個隱式的顯式。 – Boon 2014-09-01 16:46:53

+1

以beta開頭的測試版6發行說明中的​​部分「大量的Foundation API已針對可選一致性進行了審計......」在這種情況下也很有趣。 – 2014-09-01 16:48:55

回答

3

在這種特殊情況下,AnyObject!的返回是SDK中的一個錯誤(從技術上講,這只是他們使用自動Swiftifier並且尚未手動修復它的地方)。 JSONObjectWithData絕對可以返回nil。來自文檔:

返回值: 來自JSON數據的基礎對象,如果發生錯誤,則返回nil。

克里斯正在從可能的崩潰中拯救這個值,將它移動到一個明確的可選項,而不是一個實際上可能是ni的隱式可選項。

+0

謝謝Rob。所以在正常情況下,如果一個函數被正確的聲明,你不應該將一個隱式解包的可選項分配給一個顯式的,正確的? – Boon 2014-09-01 16:45:58

+2

Rob,「AnyObject!的返回是一個錯誤... [因爲這個方法]絕對可以返回'nil'。」雖然返回'AnyObject?'可能是一個更好的設計,但我不確定我是否將其描述爲一個「bug」。 AnyObject!是一個隱式解包的可選項,因此可以是'nil'(事實上,它只在返回值_could_爲'nil'的上下文中才有意義)。因此,返回值可能爲'nil'的事實與'AnyObject!'返回類型不兼容。也許我誤解了你的觀點...... – Rob 2014-09-01 17:42:14

+2

@Rob Rob從技術上說是一個bug,但你可以把它看作是一種默認的持有位置,而所有現有的SDK方法都可以得到Swififying的愛。對於* Swift *,這裏的正確返回類型將是一個真正的Optional,所以調用者會得到提示返回的結果可能是零。如果你願意,你不能從SDK方法的隱式解包可選返回中知道值是否可以爲零,所以在這種情況下,顯式可選是更好的「文檔」。 – 2014-09-01 19:58:26

0

你應該總是使用這種方法時,你可以更改Implicit Unwrapped Optional通過API爲還Xcode的未來版本將嘗試更換他們的API的從Implicit Optionals typeexplicit optional和測試6和5這種做法已經開始,很多的API返回Optional Type已改爲使用explicit optional type.The專家的建議是爲了避免Implicit Unwrapped Optional只要有可能,因爲你只要nil使用你必須明確地解開價值optional(explicit)類型展開automatically.While所以你做到這一點通過把一個if條件得到崩潰或者如果你真的確定它不會沒有零比你可以解開它沒有if(但你應該總是檢查nil例)。

JSONObjectWithData可以返回nil因爲你不知道什麼是evilData,如果它不能在json轉換,你會得到nil值,如果你嘗試在代碼中使用jsonResponseimplicit optional type其他地方比你的應用程序將在運行時崩潰。這就是爲什麼克里斯使用explicit optional照顧這種情況下,在其他地方使用jsonResponse不會自動打開包裝到零,這可能會導致崩潰。如果你自己用ifoptional binding解開代碼,你可以避免崩潰和顯示一些含義完整的信息。

+2

(文體上的注意:後面的勾號「''」代表'代碼',而不是一般的重點。用'back ticks'來標記'每一個重要的短語'都不會'改善''可讀性'。還有其他標記方法,如* italics *或** bold face ** :) – 2014-09-01 16:55:00

+0

感謝@MartinR我將在未來照顧 – codester 2014-09-01 16:56:53

-1

隱式解包的可選項仍然是可選的,儘管它保證有一個值。

將正式可選的隱式解包可選項指定爲合法。

因此,如果你的應用中有一個線性邏輯,你聲明瞭一個可選變量,然後用一個隱式解包的可選變量初始化它,那麼使用非可選變量會更好。

但是在某些情況下,您可以定義一個可選變量(假設在函數的開始處),然後基於條件,流,if等,可以爲其分配一個來自不同函數的值 - 如果至少其中一個可以返回一個正常的可選項,那麼你必須聲明該變量爲可選項。

但在這種情況下,即使所有用於爲可選/非可選變量賦值的函數總是返回一個非可選或(至少其中之一)隱式解包的可選項,與可選的聲明,因爲在將來你可能會返回一個正常的可選代碼的新分支。

最後,非常有趣的是,這似乎很好地工作

let x: Int! = nil 

,而我不得不承認我預期引發運行時異常。知道這一點,我認爲從現在開始,當函數聲明返回隱式解包時,我總是會使用可選的。

更多的測試:

func test() -> Int! { 
    return nil 
} 

let q1: Int? = test() // it works, q1 = nil (expected) 
let q2: Int! = test() // it works, q2 = nil (unexpected) 
let q3: Int = test() // runtime exception (expected) 

更新:這是documentation說什麼來代替:

如果您嘗試訪問的隱含展開可選當它不包含一個值,你會觸發運行時錯誤。結果與在不包含值的普通可選項後放置感嘆號完全相同。

這意味着:分配nil是好的,但只要它被訪問(即,分配給另一變量,在表達式中使用的,等等),它會觸發錯誤

+3

爲什麼期望將nil分配給隱式解包的可選值以引發運行時異常?這與將nil分配給普通的可選項一樣有效。 !!只意味着您在訪問它時不必手動打開它;它仍然可以保持零價值。 – 2014-09-01 19:52:41

+1

@MattGibson:我只是沒有意識到,只有當它被訪問時纔會拋出錯誤(請參閱我的答案底部的更新答案)。這是有道理的,因爲在引擎蓋下它仍然是可選的,所以分配零是合法的。 – Antonio 2014-09-01 20:07:56