我在Playground中测试Swift 2.0和新关键字defer
:
func branch() -> String {
var str = ""
defer { str += "xxx" }
str += "1"
let counter = 3;
if counter > 0 {
str += "2"
defer { str += "yyy" }
str += "3"
}
str += "4"
return str
}
let bran = branch()
我希望bran
为"123yyy4xxx"
,但实际上是"123yyy4"
为什么我推迟(str += "xxx")
无法按预期工作?
答案 0 :(得分:7)
延迟语句推迟执行,直到退出当前范围。
苹果说的话。所以defer语句将在return语句之后执行。这就是为什么你看不到预期结果的原因。
答案 1 :(得分:7)
Greg是正确的,如果你想用你的代码获得相同的结果,那么你可以这样做:
var str = ""
func branch() {
str = ""
defer { str += "xxx" }
str += "1"
let counter = 3
if counter > 0 {
str += "2"
defer { str += "yyy" }
str += "3"
}
str += "4"
}
branch()
str //"123yyy4xxx"
答案 2 :(得分:5)
首先:defer
被执行,因为您可以清楚地看到向其添加print(str)
。
现在解释为什么返回值不反映更改的值:
这样做的原因是String
是不可变的 - 每当您编写str += something
时,您都会创建一个全新的String
实例并将其存储在str
内。
如果您编写return str
,则会返回str
的当前实例123yyy4
。然后调用defer
并将全新且无关的String
123yyy4xxx
分配给str
。但这不会改变String
中存储的先前str
对象,它只会覆盖它,因此不会影响已经“发生”的return
。
如果您更改方法以使用NSMutableString
,则您将始终使用相同的实例,因此结果将正确输出123yyy4xxx
:
func branch() -> NSMutableString {
var str = NSMutableString()
defer { str.appendString("xxx") }
str.appendString("1")
let counter = 3;
if counter > 0 {
str.appendString("2")
defer { str.appendString("yyy") }
str.appendString("3")
}
str.appendString("4")
return str
}
let bran1 = branch()
在该代码中,返回返回存储在str
中的实例,并且延迟更改实例,它不会分配新实例,但会更改已存在的实例。
为了便于解释,您可以尝试在不同阶段查看str
的内存地址:
return
str
块defer
之前
对于NSMutableString
,所有三种情况都会产生相同的内存地址,这意味着实例保持不变。然而,String
打印两个不同的内存地址,导致返回的String指向someAddress
,延迟的指向someOtherAddress
。