2012-07-11 20 views
6

Bueno, estoy trabajando en un proyecto que no es ARC, pero use Philipp Kyeck's socketio library que se escribe utilizando ARC. Estoy utilizando el método explicado en this fusionar proyecto no ARC y biblioteca ARC.Liberar un objeto en un proyecto que no sea ARC, el objeto se declara en una biblioteca ARC

En mi archivo ViewController Estoy inicialización del socket usando

SockIO *chatSockIO = [[SocketIO alloc] initWithDelegate:self]; 

y cuando necesito desconectar, me llaman

[chatSockIO disconnect]; 

que resulta método delegado socketIODidDisconnect al fuego.

- (void) socketIODidDisconnect:(SocketIO *)socket{ 
    [chatSockIO release]; ==> is this call needed? 
} 

Ahora mi pregunta es sobre la línea [chatSockIO release]. ¿Deberíamos liberar un objeto que está definido en modo ARC, pero que se usa en un proyecto que no es de ARC?

Ahora bien, cuando probé la versión, que tiene una excepción diciendo

-[SocketIO retain]: message sent to deallocated instance 0x6fec370 

pero cuando me comentó que la línea, estoy consiguiendo una pérdida de memoria y dealloc en mi objeto de biblioteca no conseguir denominado en absoluto

Bounty Time !!

Olvide la biblioteca que mencioné, bloquee mi código y gotea .. ¿Cuál es la práctica habitual al usar un objeto definido mediante el método ARC, en un proyecto que no es ARC? ¿Debería solo asignarlo, o debería asignarlo y liberarlo después de su uso?

EDITAR: Un poco más de información.

Ejecuto zombie instrument en el crash, y esto es lo que tenía que decir .. Muestra la llamada para asignar y liberar funciones.

# Address  Category Event Type RefCt Timestamp  Size Responsible Library  Responsible Caller 
0 0x72d5da0 SocketIO Malloc  1  00:09.700.274 64  MyProject   -[MyViewController sendRequestForSocketIOPush] 
1 0x72d5da0 SocketIO Retain  2  00:09.700.317 0  MyProject   -[SocketIO initWithDelegate:] 
2 0x72d5da0 SocketIO Release  1  00:09.700.320 0  MyProject   -[SocketIO initWithDelegate:] 
3 0x72d5da0 SocketIO Retain  2  00:09.700.440 0  Foundation   -[NSURLConnectionInternal initWithInfo:] 
4 0x72d5da0 SocketIO Retain  3  00:10.413.717 0  Foundation   -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] 
5 0x72d5da0 SocketIO Release  2  00:10.413.761 0  Foundation   -[NSURLConnectionInternalConnection invokeForDelegate:] 
6 0x72d5da0 SocketIO Retain  3  00:10.413.797 0  Foundation   -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] 
7 0x72d5da0 SocketIO Release  2  00:10.413.811 0  Foundation   -[NSURLConnectionInternalConnection invokeForDelegate:] 
8 0x72d5da0 SocketIO Retain  3  00:10.413.816 0  Foundation   -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] 
9 0x72d5da0 SocketIO Release  2  00:10.415.087 0  Foundation   -[NSURLConnectionInternalConnection invokeForDelegate:] 
10 0x72d5da0 SocketIO Retain  3  00:10.415.214 0  Foundation   -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] 
11 0x72d5da0 SocketIO Release  2  00:10.415.216 0  Foundation   -[NSURLConnectionInternalConnection invokeForDelegate:] 
12 0x72d5da0 SocketIO Release  1  00:10.415.275 0  Foundation   -[NSURLConnectionInternalConnection invokeForDelegate:] 
13 0x72d5da0 SocketIO Retain  2  00:10.969.432 0  GraphicsServices GSEventRunModal 
14 0x72d5da0 SocketIO Release  1  00:10.969.433 0  GraphicsServices GSEventRunModal 
15 0x72d5da0 SocketIO Retain  2  00:10.969.434 0  GraphicsServices GSEventRunModal 
16 0x72d5da0 SocketIO Release  1  00:10.969.456 0  GraphicsServices GSEventRunModal 
17 0x72d5da0 SocketIO Retain  2  00:10.969.459 0  GraphicsServices GSEventRunModal 
18 0x72d5da0 SocketIO Retain  3  00:10.969.488 0  Foundation   -[NSCFTimer initWithFireDate:interval:target:selector:userInfo:repeats:] 
19 0x72d5da0 SocketIO Release  2  00:10.976.115 0  MyProject   -[SocketIO setTimeout] 
20 0x72d5da0 SocketIO Retain  3  00:10.976.125 0  Foundation   -[NSCFTimer initWithFireDate:interval:target:selector:userInfo:repeats:] 
21 0x72d5da0 SocketIO Release  2  00:10.976.161 0  GraphicsServices GSEventRunModal 
22 0x72d5da0 SocketIO Retain  3  00:13.935.328 0  GraphicsServices GSEventRunModal 
23 0x72d5da0 SocketIO Release  2  00:13.935.373 0  MyProject   -[SocketIO setTimeout] 
24 0x72d5da0 SocketIO Retain  3  00:13.935.399 0  Foundation   -[NSCFTimer initWithFireDate:interval:target:selector:userInfo:repeats:] 
25 0x72d5da0 SocketIO Release  2  00:13.935.685 0  MyProject   -[SocketIO onDisconnect] 
26 0x72d5da0 SocketIO Release  1  00:13.935.705 0  MyProject   -[MyViewController socketIODidDisconnect:] 
27 0x72d5da0 SocketIO Release  0  00:13.935.716 0  GraphicsServices GSEventRunModal 
28 0x72d5da0 SocketIO Zombie  -1  00:13.936.298 0  GraphicsServices GSEventRunModal 
+0

No es necesario cambiar el archivo de clase ARC simplemente agregue '-fobjc-arc' en el indicador del compilador del archivo de clase – Sumanth

+0

@Sumanth Desafortunadamente tengo una biblioteca escrita en ARC, y esa biblioteca usa 3 o 4 otras bibliotecas todas sigue a ARC. Este método de biblioteca estática es mejor en ese caso, supongo ... Además, incluso si clasifico todos mis archivos de clase ARC utilizando indicadores de compilación, estoy asignando y utilizando el objeto sockIO en mi archivo de proyecto, que está escrito en modo no ARC. Y si lo hago alocar/retener en un archivo que no sea ARC, debo liberarlo. – Krishnabhadra

+2

http://blog.mugunthkumar.com/articles/migrating-your-code-to-objective-c-arc/ - este es realmente un gran tutorial sobre [mezclar] código ARC/no-ARC ¿También sabe de 'NS_RETURNS_NON_RETAINED' y' NS_RETURNS_RETAINED'? –

Respuesta

3

Para responder a su pregunta:

Si se utiliza un objeto ARC gestionados desde el código no-ARC, se utiliza simplemente como lo haría con un objeto no ARC: Si crea o retenerlo, tiene que soltarlo o liberarlo.

En cuanto a su problema:

En el de sus comentarios que usted ha mencionado que ha intentado solucionar el problema con la inicialización como esta

self.chatSockIO = [[[SocketIO alloc] initWithDelegate:self] autorelease]; 

y en socketIODidDisconnect

self.chatSockIO = nil; 

Eso debería funcionar bien, siempre que la propiedad chatSockIO tenga retain sem travesuras, y que solo se usa un objeto SocketIO a la vez.

La salida del zombi da una pista sobre lo que va mal:

  • En la penúltima línea, se suelta el objeto, la cuenta de retención se reduce a 0, y el objeto se cancela la asignación. Eso es lo que esperarías.
  • En la última línea, sin embargo, se intenta retener el objeto del ciclo de ejecución. Usted sabe que es un retener debido a la excepción que obtiene sin NSZombie.
  • Eso significa que aunque haya terminado con el objeto, todavía recibe llamadas de algún lugar. Esto es inesperado.

Podría ser algo en el código o un error en una de las bibliotecas que está utilizando. Sólo una corazonada: En SocketIO.m reemplazar estas líneas en -onDisconnect

if (_webSocket != nil) { 
    [_webSocket close]; 
} 

con

if (_webSocket != nil) { 
    [_webSocket close]; 
    _webSocket.delegate = nil; 
} 
0

En mi experiencia, no mezclaría ARC y no ARC esperan pequeños trozos de código. Perdí demasiado tiempo para tratar de encontrar fugas y errores.

Si no se puede convertir a su programa ARC, considere el uso de la versión no-ARC de sockIO: https://github.com/pkyeck/socket.IO-objc/tree/non-arc

Eso probablemente le ahorrará muchos dolores de cabeza.

+0

Primero utilicé la versión que no es ARC, pero todavía usa cocoa-websocket cuando la versión de ARC se actualizó para usar SocketRocket. Es por eso que me vi obligado a usar la versión ARC. – Krishnabhadra

+0

Además, el uso de clases ARC en proyectos que no son de ARC utilizando el método de biblioteca estática funciona bien. Puedo ignorar la filtración que mencioné ya que esa parte del código se ejecuta solo una vez en mi aplicación y la magnitud de la fuga es muy pequeña. Puedo comentar la línea de lanzamiento y continuar ... Pero solo quería saber cuál es el procedimiento adecuado al fusionar archivos ARC y no ARC utilizando el método de biblioteca estática. – Krishnabhadra

+0

Espero que realmente necesite liberarlo. Pero tal vez su problema aquí es que no tiene una referencia al objeto SockIO mientras ejecuta el resto del código. Intente agregar el objeto sockIO a una propiedad fuerte y vuelva a agregar la versión? –

0

Sentí problemas similares. Lo solucioné estableciendo @property(nonatomic, retain) sobre la clase. En su caso debe ser,

en .h

@property(nonatomic, retain) SockIO *socketIO; 

en .m

@synthesize socketIO; 
    chatSockIO = [[SocketIO alloc] initWithDelegate:self]; 

Y usted no conseguirá bloquee su aplicación de nuevo!

+0

Bueno, yo hice lo que sugiere, hice de chatSockIO una propiedad y la conservé .. Cuando asigné, cambié el código a 'self.chatSockIO = [[[SocketIO alloc] initWithDelegate: self] autoRelease];'.En el método de delegado 'socketIODidDisconnect' Reemplacé '[chatSockIO release]' con 'self.chatSockIO = nil'. Todavía estoy obteniendo el colapso .. – Krishnabhadra

+0

No, no use self.chatSockIO - lo retiene doblemente. El código de ejemplo está estructurado de modo que el ivar se establece con el valor retenido. –

+0

@DavidH nope .. Estoy usando liberación automática junto con self.chatSockIO ... ¿Lo has notado? – Krishnabhadra

0

Los objetos ARC y no ARC se mezclan bien. Las clases que se implementan usando ARC se pueden usar de manera segura desde código que no sea ARC. Siempre que haya un error de propiedad, probablemente el problema esté en su código.

Sin ver el código no es posible encontrar el error, pero es probable que sea un simple sobrerelleno.

vistazo a todos los lugares en donde la traza MyProject Instrumentos muestra un evento Release, como -[SocketIO setTimeout], -[SocketIO onDisconnect] y -[MyViewController socketIODidDisconnect:]. Compruebe si hay transferencias de propiedad inadecuadas, como la asignación de una variable de instancia manejada por una propiedad de retención o similar.

+0

En los 3 métodos que mencionó, solo en '- [MyViewController socketIODidDisconnect:]' Estoy liberando el objeto socket io. Solo se llama una vez (ese fue mi primer puerto de escala, pensando que de alguna manera se llama al delegado dos veces por una desconexión, y se libera el objeto dos veces). En cuanto al código completo, no hay mucho que haya omitido. El único otro uso del objeto 'socketIO' es cuando se reciben o envían los datos. No estoy reteniendo ni liberando o lanzando automáticamente allí. Además, las funciones 'setTimeout' y' onDisconnect' son funciones dentro de la biblioteca y no las he llamado directamente. – Krishnabhadra

+0

También esto podría ser un error en la biblioteca, ya que exagera la cosa en alguna parte ... No estoy seguro de eso sin embargo ... Es por eso que reformulé es una pregunta más genérica. – Krishnabhadra

+0

Correcto, parece que las funciones 'GSEventRunModal' de GraphicsServices realmente realizan el lanzamiento excesivo. Debería ver las pilas individuales en el historial de retención de estas llamadas para comprender por qué se realizan. Puede ser un problema de la biblioteca que está utilizando. –

0

Actualmente estoy trabajando en un proyecto que hice algo similar y la forma en que lo resolví fue cambiar el proyecto que no era de ARC a ARC. Xcode transfiere todo para usted y para mí resolvió todas mis pérdidas de memoria y otros problemas.

Para volver a la ARC es necesario:

1. Haga clic en Editar-> Refactor-> Convertir en Objective-C ARC

2. Haga clic en su objetivo de proyectos y en la caída desplegable, seleccione los archivos que desea convertir a ARC

3. Haga clic en Comprobar una vez que haya seleccionado los archivos correctos

4. Haga clic en Siguiente y espere hasta que finalice la conversión.

5. Haga clic en el botón "Actualizar" para actualizar su código.

6. revisión su código

Espero que ayude. Me ayudó

1

Esto no puede resolver su problema, pero en cualquier caso es normalmente una idea terrible para liberar un objeto en una llamada delegado - puede ser desasignado mientras todavía está trabajando, y particularmente si el objeto está bajo ARC, puede no tener un método dealloc.

Así convertir su estrecha llamada delegado a esto:

- (void) socketIODidDisconnect:(SocketIO *)socket 
{ 
    chatSockIO.delegate = nil; // don't want any more messages 
    dispatch_async(dispatch_get_main_gueue(), ^{ self.chatSockIO = nil; }); // typed in text editor 
    // your question - is the release needed? Well, under virtually every scenario yes, but I don't know this framework 
} 

Si esto soluciona el problema o no, usted debe hacer el lanzamiento de esta manera - en el hilo principal después ha regresado al delegado. Si observa su código, debe hacerlo EXACTAMENTE con esta clase ARC como lo haría con una clase normal. La interoperabilidad es excelente, utilicé varios proyectos NO ARC en mi aplicación ARC, y otros han hecho con éxito al revés.

Cuestiones relacionadas