2015-03-13 72 views
9

所以我知道'!'和「?」,我只是想知道什麼是調用一個可選變量Swift:調用可選變量的方法

var bar: Bar? = nil 

bar?.doSomething() // this will be valid, but wouldn't call doSomething 
bar!.doSomething() // Given error: EXC_BAD_INSTRUCTIONS (Obviously) 

但是,當「酒吧」不是零,這兩個方法,調用都是有效的方法時,使用它們的最好方法。

bar = Bar() 
bar?.doSomething() // Valid 
bar!.doSomething() // Valid 

所以我的問題是,什麼是調用一個可選的變量的方法最好的方式,我個人使用:

if bar != nil { 
    bar!.doSomething() 
} 

或將條.doSomething()做完全一樣嗎? ?

+0

經驗法則:每次你可以避免寫一個'!',這樣做(除了否定'Bool')。這包括例如強制downcast'as!'。 '!'的意思是'嘿!不要這樣做!這很危險!我警告過你!' – 2015-03-13 09:07:17

+3

'!'的意思是我確切地知道我在做什麼!我是開發人員,我決定如何運行我的程序!這不取決於某個變量來決定是否應該調用一個方法!'。在我看來Objective-C開發人員傾向於過度使用'?'。如果你可以將可選的東西鏈接在一起,而且不應該是可選的(從軟件設計的角度來看),那麼你正在模擬Objective-C中友好的零。 – 2015-03-13 09:13:11

+2

@MatthiasBauch'!'表示'我是開發者,我從不犯錯!我的程序總是完全按照!我決定!' 在我看來,'!'的意思是簡單的'這不應該是零,不要繼續,如果它。' – Krzak 2015-03-13 09:20:26

回答

18

我認爲這是不好的建議,以避免bar?.doSomething()並始終使用if let bar = bar { ... }來代替。

主要有兩個原因:

首先,bar?.doSomething()只是更加簡潔。如果你在條件表達式中只寫了一條語句if let,那麼你應該問問自己,如果你不想用較短的版本把代碼放在一行上。

雖然這是完全合法的代碼..

if let thing = thing { 
    thing.bar() 
} 

..下面的代碼是一樣的法律,只是短了很多..

thing?.bar() 

其次,更重要和核心這個問題,他們是不一樣的!if let是一個組合測試,可選展開和分配,而bar?做的東西叫做可選鏈接

後者在許多情況下非常有用,可以讓你編寫更好的代碼。例如:

它可以用來替代這個..

var imageGenerator: ImageGenerator? 

if let generator = imageGenerator { 
    myView.image = generator.generateImage() 
} else { 
    myView.image = nil 
} 

..簡單地:

myView.image = self.imageGenerator?.generateImage() 

這樣做的原因是因爲可選鏈接返回nil儘快因爲它在中遇到nil。而且由於UIImageView有一個image: UIImage?,它取那個零值。即使它來自一個ImageGenerator?

當與無合併運算??組合是更加有用。

現在,你可以把這個代碼..

var imageGenerator: ImageGenerator? 

if let generator = imageGenerator { 
    myView.image = generator.generateImage() 
} else { 
    myView.image = DefaultImage 
} 

..到..

myView.image = generator?.makeImageGenerator() ?? DefaultImage 

..這是方式更簡潔。

而且由於可選鏈接作品上 ..你甚至可以這樣做:

myView.image = delegate?.makeImageGenerator()?.generateImage() ?? DefaultImage 

這將成爲..

if let delegate = delegate { 
    if let generator = delegate.generatorForImage() { 
     if let image = generator.generateImage() { 
      myView.image = image 
     } else { 
      myView.image = DefaultImage 
     } 
    } else { 
     myView.image = DefaultImage 
    } 
} else { 
    myView.image = DefaultImage 
} 

..如果你沒有使用可選鏈接無合併操作員

(是的myView.image = DefaultImage可以是有條件在年底完成,但是這意味着你仍然必須引入額外的代碼來檢查它是否被設置。它不會是短得多。)

有兩個新的花樣:-)

4

當你

bar?.doSomething() 

它被稱爲可選鏈接:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html

這意味着,如果酒吧是零,也不會繼續DoSomething的方法,但返回一個零。如果你想處理它爲零的情況,你應該檢查一個對象是否包含零。你也可以像這樣做,通過可選的結合:

if let unwrappedBar = bar { 
    unwrappedBar.doSomething() 
} else { 
    doSomeOtherThing() // In case it's nil 
} 

這使得可用的,如果讓語句稱爲unwrappedBar暫時不變內的值(你可以給它任何其他的名字,如果你想),如果不是零。

您還可以使用更短的語法與可選的鏈接和合並操作:

bar?.doSomething() ?? doSomeOtherThing() 

下面是關於不同的方式來訪問可選值的更多信息:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID330

+0

偉大的,我應該使用**,如果讓更多的經常 – 2015-03-13 09:20:15

+0

這實際上不是閉包。 – 2015-03-13 12:57:53

+0

@StefanArentz這是真的,謝謝。希望現在是正確的。 :) – alkku 2015-03-14 07:26:36

2
bar?.doSomething() 

是調用的最佳方式一個可選變量的方法。如果酒吧不是零,它只會叫做某事。你寫最少的代碼,這是完全一樣實現一個if let檢查

if let bar = bar { 
    bar.doSomething() 
} 
+1

我認爲這是更好的建議比'總是使用'如果讓''。這種形式存在的原因是:它很簡潔。 'if let'仍然有用,但在我看來並不適用於單個方法調用 - 如果您多次使用'bar',那麼'if let'可能會更好。 – 2015-03-13 13:00:01