Durante años he estado siguiendo un gran patrón llamado Target-Action que dice así:¿El patrón de diseño Target-Action se convirtió en una mala práctica bajo ARC?
Un objeto llama a un selector especificado en un objeto de destino específico cuando llega el momento de llamar. Esto es muy útil en muchos casos diferentes en los que necesita una devolución de llamada simple a un método arbitrario.
He aquí un ejemplo:
- (void)itemLoaded {
[specifiedReceiver performSelector:specifiedSelector];
}
Bajo ARC ahora resulta que hacer algo como esto, de repente se convirtió en peligroso.
Xcode lanza una advertencia que dice así:
PerformSelector puede causar una fuga debido a su selector se desconoce
Por supuesto, el selector es desconocida ya que como parte del diseño Meta-Acción patrón puede especificar el selector que desee para recibir una llamada cuando sucede algo interesante.
Lo que más me molesta acerca de esta advertencia es que dice que puede haber una posible pérdida de memoria. Desde mi punto de vista, ARC no dobla las reglas de administración de memoria, sino que simplemente automatiza la inserción de mensajes de retención/liberación/liberación automática en las ubicaciones correctas.
Otra cosa a tener en cuenta aquí: -performSelector: tiene un valor de retorno id
. ARC analiza las firmas de métodos para descubrir mediante la aplicación de convenciones de nomenclatura si el método devuelve un +1 retener el objeto de recuento o no. En este caso, ARC no sabe si el selector es una fábrica -newFooBar
o simplemente llama a un método de trabajo no sospechoso (que casi siempre es el caso con Target-Action). En realidad, ARC debería haber reconocido que no esperaba un valor de retorno, y por lo tanto, olvidarme de cualquier potencial +1 de retención del valor de retorno contado. Mirándolo desde ese punto de vista, puedo ver de dónde viene el ARC, pero aún hay demasiada incertidumbre sobre lo que realmente significa en la práctica.
¿Eso significa ahora que bajo ARC algo puede ir mal, lo que nunca ocurriría sin ARC? No veo cómo esto podría producir una pérdida de memoria. ¿Puede alguien dar ejemplos de situaciones en las que es peligroso hacerlo y cómo se crea exactamente una fuga en ese caso?
Realmente busqué en Google, pero no encontré ningún sitio explicando por qué.
Tiene toda la razón. Pero en mi caso ignoro completamente el valor de retorno, lo que en una consecuencia lógica significa que no puede haber un problema en esta ubicación. Incluso he intentado convertir el void, el bridging, __unsafe_unretained, etc. - la única forma de deshacerse de él es pasar a bloques (lo que causa una plétora de otros problemas) o deshabilitar la advertencia en la configuración de fases de compilación. –
Ver mi edición para desactivar la advertencia por solo un pedacito de código. – mattjgalloway
Dos cerebros, el mismo pensamiento. ¡Estupendo! :-) (mecanografió mi respuesta al mismo tiempo. contiene más información sobre la desactivación de la advertencia) –