I have a Swift class that needs to store a table of its own methods. Unfortunately this is causing a reference cycle, because its table retains references to self
via the methods it stores.
Example leaky code below:
typealias Callback = ()->()
class CycleInducingClass : NSObject {
var myCallbacks = [Callback]()
override init() {
super.init()
myCallbacks.append(myInternalFunction)
}
func myInternalFunction() {
NSLog("lolol: %d", self.myCallbacks.count)
}
}
The only solution I've found so far is to instead do this:
myCallbacks.append({[unowned self] in self.myInternalFunction()})
That's pretty ugly, and prone to error. Any better ideas? Is there some trick for making the function references themselves be weak? i.e. to make the myCallbacks
array of type myCallbacks : [WeakCallback]()
or something? As far as I can tell I can't even build a convenience function weaken
as syntactic sugar over the ugly closure wrapper above.
You can certainly build a function for this. I don't know if it makes it dramatically better, but it is less error-prone.
func methodPointer<T: AnyObject>(obj: T, method: (T) -> () -> Void) -> (() -> Void) {
return { [unowned obj] in method(obj)() }
}
...
myCallbacks.append(methodPointer(self, CycleInducingClass.myInternalFunction))
Alternately, you could manage your callbacks as method pointers:
typealias Callback = (CycleInducingClass) -> () -> Void
...
myCallbacks.append(CycleInducingClass.myInternalFunction)
In that case, you'd need to pass self
when you called them (which may be fine if you don't actually do this a lot):
self.myCallbacks[0](self)()
All of this is based on the fact that a method on type T
with signature (input) -> (output)
is equivalent to a function with the signature (T) -> (input) -> (output)
.
In case you're curious (I was), overriding works correctly in this case. So if you subclass CycleInducingClass
and override myInternalFunction
, the correct version will be called. (That actually surprises me a little, and I don't yet know exactly why it works, but it does.)
EDIT: Here's the answer to that: https://devforums.apple.com/message/1036509#1036509
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments