我在Swift中使用ReactiveCocoa如下:
registerButton?.rac_signalForControlEvents(UIControlEvents.TouchUpInside).subscribeNextAs(registerButtonTapped)
private func registerButtonTapped(button: UIButton){
// Method here
}
这会创建一个保留周期。
我知道解决方案如下:
registerButton?.rac_signalForControlEvents(UIControlEvents.TouchUpInside).subscribeNextAs({ [weak self] (button:UIButton) in
self?.registerButtonTapped(button)
})
但是这强制我使用subscribeNextAs
块而不是更好的oneliner传递方法。
知道如何在没有保留周期的情况下使用oneliner吗?
答案 0 :(得分:12)
好的,所以由Jakub Vano链接的the answer很棒,但它并非相当通用。它限制您使用没有参数的函数并返回Void
。使用Swift泛型,我们可以更聪明地使用接受任何参数的函数并使用任何返回类型。
首先,对于weak
关系,必须使用对象。结构不能被弱化。因此,我们将实例类型约束为AnyObject
,这是一个所有类都符合的协议。我们的函数声明如下所示:
func applyWeakly<Type: AnyObject, Parameters, ReturnValue>(instance: Type, function: (Type -> Parameters -> ReturnValue)) -> (Parameters -> ReturnValue?)
因此该函数接受一个实例,以及一个接受实例并返回Parameters -> ReturnValue
函数的函数。请记住,Swift中的闭包和函数是可以互换的。整齐!
请注意,我们必须返回可选 ReturnValue
,因为该实例可能会变为nil
。我稍后会讨论如何解决这个问题。
好了所以现在你需要知道一个非常巧妙的技巧:Swift instance methods are actually just curried class methods,这完全符合我们的需求
现在我们可以使用 class 函数调用applyWeakly
,当您使用实例调用它时,它会返回实例函数。 applyWeakly
实现非常简单。
func applyWeakly<Type: AnyObject, Parameters, ReturnValue>(instance: Type, function: (Type -> Parameters -> ReturnValue)) -> (Parameters -> ReturnValue?) {
return { [weak instance] parameters -> ReturnValue? in
guard let instance = instance else { return nil }
return function(instance)(parameters)
}
}
超级。那你怎么用这个呢?我们来看一个非常简单的例子。我们有一个带有一个包含闭包的参数的类,该闭包将引用它自己的实例方法(这只是演示了引用循环问题 - 你的问题涉及两个对象,但我简化为一个)。
class MyClass {
var closure: (String -> String?)!
func doThing(string: String) -> String {
return "hi, \(string)"
}
init() {
closure = doThing // WARNING! This will cause a reference cycle
closure = applyWeakly(self, function: MyClass.doThing)
}
}
我们必须为closure
类型使用隐式解包的可选项,以便我们可以在init
函数中引用实例方法。没关系,只是这个例子的限制。
所以这很棒,而且会有效,但我们的closure
类型为String -> String?
,但我们的doThing
类型为String -> String
,这有点蠢。为了返回非可选字符串,我们需要强制解包可选()或使用unowned
。
无主引用就像弱引用,除非它们是非归零的。这意味着如果对象被取消分配并且您使用对它的引用,您的应用程序将会爆炸。但是,在您的情况下,它是适用的。 Here's more info关于无主和弱者。
applyUnowned
函数如下所示:
func applyUnowned<Type: AnyObject, Parameters, ReturnValue>(instance: Type, function: (Type -> Parameters -> ReturnValue)) -> (Parameters -> ReturnValue) {
return { [unowned instance] parameters -> ReturnValue in
return function(instance)(parameters)
}
}
我希望澄清事情 - 很乐意回答任何后续问题。这个问题已经在我的脑海里浮现了一段时间,我很高兴终于记下了我的想法。