传递直接引用或关闭

pass direct reference or closure

来自不同的语言背景,其中将方法传递给另一个对象的方式不同,如下所示(方法 A),但我注意到 Objective-C 和 [= 中传递块的风格14=],SWIFT 中推荐的方法是什么?为什么? (有利有弊?)

class Messenger {
    private var _method: ((String) -> ())

    init(method: (String -> ())) {
        _method = method
    }
}

class Test {
    init() {
        Messenger(method: self.callback) //approach A

        Messenger({
            message in self.callback(message) //approach B - Wrapper/Block style
        })
    }

    func callback(message: String) {
        println(message)
    }
}

您的方法 B 将允许您在 message inself.callback(message) 之间插入额外的语句。如果没有这样的附加声明(如您的逐字示例),我会赞成方法 A.

您的方法 A 是可行的方法。方法 B 确实没有用处——您正在声明一个匿名函数,它接受一个参数并且不对它做任何事情,而是将它用作另一个函数的参数,callback。本质上就像这样说:

func f(arg1: Int) {
    // do nothing but call g
    g(arg1)
}
f(1)        // no different to calling g(1)
takeFunc(f) // no different to passing in g

重要的是要认识到,使用闭包表达式语法 let f: Int->Bool = { i in etc } 声明的函数和使用 func 关键字声明的函数 func f(i: Int)->Bool { etc } 几乎是同一回事。有细微的差别,但不是根本性的。

关于强引用的担忧 - 选项 B 中的闭包表达式并没有真正帮助这种情况。在选项 A 中,您通过传入指向实例成员函数的指针来传递对 self 的隐式引用。在选项 B 中,您声明一个“捕获”self 的匿名闭包,然后传递它,但是存储的匿名函数将以与存储 self.memfun 相同的方式使 self 保持活动状态,只是有一个额外的间接级别。事实上,很容易忘记通过闭包表达式捕获 self 可能存在风险,如果你不小心隐式地捕获 Swift 并强制你放置一个显式的 self ,那么 Swift 会警告你] 在那里(当你知道捕获不是问题时,有时会非常烦人,例如在调用 mapfilter 时引用 self)。

要编写不捕获 self 的回调函数,您必须使用 capture list:

    Messenger { [weak self] message in // weak or unowned depending on how Messenger is being used 
        self?.callback(message)  // if weak, self needs to be optional
        return // return needed since otherwise it will attempt to return ()?
    }

顺便说一下,写更多 Swift-y Swift 的最好方法是去掉很多多余的括号 :-)

例如

// no need to wrap entire function type in (),
// and single argument types (i.e. 1-element tuples)
// don’t need () surrounding them: 
private var _method: String -> ()

而不是

private var _method: ((String) -> ())

Messenger { // closure exprs can be outside the () of functions 
            // when they’re the last argument (and () can be 
            // left out completely when they’re the only argument) 
    message in self.callback(message)
}

而不是

Messenger({
        message in self.callback(message) //approach B - Wrapper/Block style
})