我在 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
block ,而不是传递该方法的更好的 oneliner。
知道如何在没有保留周期的情况下使用 oneliner 吗?
最佳答案
好的,所以 the answer Jakub Vano 的链接很棒,但它不是相当通用的。它限制您使用没有参数并返回 Void
的函数。使用 Swift 泛型,我们可以更聪明地使用接受任何参数和使用任何返回类型的函数。
所以第一件事是,对于弱
关系,您必须使用一个对象。不能弱引用结构。所以我们将实例类型限制为 AnyObject
,这是所有类都遵守的协议(protocol)。我们的函数声明如下所示:
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 ,这非常适合我们的需求 🎉
现在我们可以调用 applyWeakly
和 class 函数,当您用实例调用它时,它会返回一个实例函数。 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)
}
}
super 棒。那么你将如何使用它?让我们举一个非常简单的例子。我们有一个包含闭包参数的类,该闭包将引用它自己的实例方法(这只是演示引用循环问题——你的问题涉及两个对象,但我简化为一个)。
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关于无主 vs 弱。
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)
}
}
我希望这能澄清一些事情——很乐意回答任何后续问题。这个问题已经在我脑海中萦绕了一段时间,我很高兴终于把我的想法记录下来。
关于swift - 将闭包作为参数传递时,ReactiveCocoa 保留循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31140451/