简体   繁体   中英

Release an object in a non-ARC project, object is declared in an ARC library

Well I am working on a non-ARC project, but use Philipp Kyeck's socketio library which is written using ARC. I am using the method explained in this tutorial merge non-ARC project and ARC library.

In my ViewController file I am initializing the socket using

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

and when I need to disconnect, I call

[chatSockIO disconnect];

which results socketIODidDisconnect delegate method to fire.

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

Now my question is about the line [chatSockIO release] . Should we need to release an object which itself is defined in ARC mode, but is used in a non-ARC project?

Now when I tried the release, I got an exception saying

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

but when I commented out that line, I am getting a memory leak and dealloc in my library object not getting called at all

Bounty Time!!

Forget the library I mentioned, crash in my code and leaks.. What is the usual practice when using an object defined using ARC method, in a non-ARC project. Should I only alloc it, or should I alloc and release it after use?

EDIT:Some more info.

I run zombie instrument on the crash, and this is what it had to say.. It shows the call to alloc and release functions.

#   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

To answer your question:

If you use an ARC-managed object from non-ARC code, you use it just as you would use a non-ARC object: If you create or retain it, you have to release or autorelease it.

Regarding your issue:

In on of your comments you mentioned that you tried to fix the problem with initializing like this

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

and in socketIODidDisconnect

self.chatSockIO = nil;

That should work fine, provided that the chatSockIO property has retain semantics, and that only one SocketIO object is used at a time.

The Zombie output gives a hint on what's going wrong:

  • In the second to last line, you release the object, the retain count drops to 0, and the object is deallocated. That is what you would expect.
  • In the last line however, it is tried to retain the object from the run loop. You know it's a retain because of the exception you get without NSZombie .
  • That means although you are done with the object, it still receives calls from somewhere. This is unexpected.

It could be either something in your code, or an error in one of the libraries you are using. Just a hunch: In SocketIO.m replace these lines in -onDisconnect

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

with

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

This may not solve your problem, but in any case its usually a TERRIBLE idea to release an object in a delegate call - it may get dealloc'd while still doing work, and particularly if the object is under ARC, may not have a dealloc method.

So convert your close delegate call to this:

- (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
}

Whether this fixes your problem or not, you should be doing the release in this manner - on the main thread AFTER the delegate has returned. If you look at your code, you should do EXACTLY with this ARC class as you would with a normal class. The interoperability is excellent, I used several NON-ARC projects in my ARC app, and others have successfully done the reverse.

In my experience I wouldn't mix ARC and non-ARC expect small small chunks of code. I wasted way to much time to try to find leaks and crash bugs.

If you can't convert your program to ARC, consider using the non-ARC version of sockIO: https://github.com/pkyeck/socket.IO-objc/tree/non-arc

That will probably save you a lot of headaches.

I had felt similar issues. I solved this by setting @property(nonatomic, retain) over the class. In your case it should be,

in .h

  @property(nonatomic, retain) SockIO *socketIO;

in .m

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

And you wont get crash your App again !

ARC and non ARC objects mix fine. Classes that are implemented using ARC can safely be used from non-ARC code. Whenever there's an ownership error the problem is probably in your code.

Without seeing code it's not possible to find the error but it's probably some simple over-release.

Look at all the places in MyProject where the Instruments trace shows a Release event, like -[SocketIO setTimeout] , -[SocketIO onDisconnect] and -[MyViewController socketIODidDisconnect:] . Check if there are improper ownership transfers, like assigning an instance variable handled by a retain property or similar.

I am currently working on a project that I did something similar and the way I solved it was to switch the non-ARC project to ARC. Xcode transfers everything over for you and for me solved all my memory leaks and other issues.

To change over to ARC you need to:

1. Click Edit->Refactor->Convert to Objective-C ARC

2. Click your projects target and in the drop down, select the files you want to convert to ARC

3. Click Check once you have selected the right files

4. Click next and wait until conversion is done.

5. Click the "Update" button to update your code.

6. Review your code

Hope that helps. It helped me

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM