basics - Hacerte débil en métodos en Swift
swift reference (4)
Ciertamente puedes construir una función para esto. No sé si lo hace dramáticamente mejor, pero es menos propenso a errores.
func methodPointer<T: AnyObject>(obj: T, method: (T) -> () -> Void) -> (() -> Void) {
return { [unowned obj] in method(obj)() }
}
...
myCallbacks.append(methodPointer(self, CycleInducingClass.myInternalFunction))
Alternativamente, puede administrar sus devoluciones de llamada como punteros de método:
typealias Callback = (CycleInducingClass) -> () -> Void
...
myCallbacks.append(CycleInducingClass.myInternalFunction)
En ese caso, deberías pasarte a ti self
cuando los llamaste (lo que puede estar bien si no lo haces mucho):
self.myCallbacks[0](self)()
Todo esto se basa en el hecho de que un método en el tipo T
con firma (input) -> (output)
es equivalente a una función con la firma (T) -> (input) -> (output)
.
En caso de que tenga curiosidad (lo estaba), la anulación funciona correctamente en este caso. Entonces, si subclasifica CycleInducingClass
y reemplaza myInternalFunction
, se myInternalFunction
la versión correcta. (Eso realmente me sorprende un poco, y todavía no sé exactamente por qué funciona, pero sí lo hace).
EDIT: Aquí está la respuesta a eso: https://devforums.apple.com/message/1036509#1036509
Tengo una clase Swift que necesita almacenar una tabla de sus propios métodos. Desafortunadamente, esto está causando un ciclo de referencia, porque su tabla conserva las referencias a self
través de los métodos que almacena.
Ejemplo de código con fugas a continuación:
typealias Callback = ()->()
class CycleInducingClass : NSObject {
var myCallbacks = [Callback]()
override init() {
super.init()
myCallbacks.append(myInternalFunction)
}
func myInternalFunction() {
NSLog("lolol: %d", self.myCallbacks.count)
}
}
La única solución que he encontrado hasta ahora es hacer esto:
myCallbacks.append({[unowned self] in self.myInternalFunction()})
Eso es bastante feo, y propenso a error. ¿Alguna idea mejor? ¿Hay algún truco para hacer que las propias referencias sean débiles? es decir, para hacer la matriz myCallbacks
de tipo myCallbacks : [WeakCallback]()
o algo así? Por lo que puedo decir, ni siquiera puedo construir una función de conveniencia weaken
como azúcar sintáctica sobre el envoltorio de cierre feo arriba.
En Swift 4 (no estoy seguro de cuándo se hizo disponible la sintaxis), simplemente haga { [weak self] (params) in }
para debilitarse. Básicamente es para [unowned self]
, ¿qué Self?
es para Self!
. El compilador incluso requiere self?.foo
lugar de self.foo
.
La respuesta de Robs funcionó para mí. Lo refactoricé para que fuera un poco más OO, así que pensé que lo compartiría aquí en caso de que ayude a alguien más:
public protocol WeakCallback{
func invoke()
}
public class WeakCallbackInstance<T: AnyObject> : WeakCallback{
private let callback: ()->Void
private weak var target: T?
public init(target: T, action: (T)->()->Void){
self.target = target
callback = { [weak target] in
action(target!)()
}
}
public func invoke(){
callback()
}
}
class ExampleUsage{
func usage(){
var callbacks = [WeakCallback]()
let one = WeakCallbackInstance(target: DummyCallbackOne(), action:DummyCallbackOne.callbackOne)
let two = WeakCallbackInstance(target: DummyCallbackTwo(), action:DummyCallbackTwo.callbackTwo)
callbacks.append(one)
callbacks.append(two)
callbacks.first?.invoke()
}
}
class DummyCallbackOne{
func callbackOne(){
}
}
class DummyCallbackTwo{
func callbackTwo(){
}
}
envuelto sin función param con bloque
myCallbacks.append({ [unowned self] in self.myInternalFunction() })
Función param envuelta con bloque
myCallbacks.append({ [unowned self] page in self.reloadData(page: page) })