2015-03-13 74 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