EASession Leaks
Asked Answered
A

2

6

I have an app that connects to an accessory, and the EASession that I create in order to communicate with the accessory leaks when you disconnect the accessory.

When the accessory connects, I get a notification of this and check EAAccessoryManager's accessories collection for an accessory with a certain name that uses a certain protocol. When I find this I create an EASession object for that accessory with code:

-(void) openSession
{
   ...  // finds accessory object

   if (accessory)
   {
      [self closeSession];
      session = [EASession alloc];
      NSLog(@"alloc :: session retainCount: %i", session.retainCount);
      [session initWithAccessory:accessory forProtocol:SmokeSignalsProtocolName]; 
      NSLog(@"init  :: session retainCount: %i", session.retainCount);

      [[session inputStream] open]; 
      [[session outputStream] open]; 

      ... // other logic (pump run loop, etc..)
   }
}

-(void) closeSession
{
    if (session)
    {
       [[session inputStream] close]; 
       [[session outputStream] close]; 
       [session release], session = nil;
    }
}

Normally I have the alloc and init on one line, but what I've found (separating it out like this) is that the alloc gives +1 retain count (as you'd expect) BUT the iniWithAccessory:forProtocol: gives it +3 retain count when I would only expect +2 retainCount from the init method.

The leaks instrument also appears to support this:

enter image description here

Step by Step look at the leaks instrument:

  1. +1 retain count :: [???Accessory openSession] - this is where I alloc a new EASession.
  2. +1 retain count :: [EAInputStream iniWithAccessory:forSession:] The input stream holds a reference back to the owning session.
  3. +1 retain count :: [EAOutputStream initWithAccessory:forSession:] The output stream holds a reference back to the owning session.
  4. +1 retain count :: [EASession iniWithAccessory:forProtocol:] I have no idea why this is increasing the retain count of EASession. I believe this is responsible for the additional retain count that I can't account for... Not sure how this is supposed to be balanced. Is this Apple's bug and I need to call release an extra time to balance things.... Very VERY weird.
  5. -1 retain count :: [EAInputStream close] Cleans up step #2 above
  6. -1 retain count :: [EAOutputStream close] Cleans up step #3 above
  7. -1 retain count :: ???Accessory closeSession] Cleans up step #1 above1

So... Why am I leaking the EASession object? What's the proper way to use a EASession object to not leak?


Edit - EADemo Does Not Leak, but ...

EADemo connects to accessories, but it does not leak. Out of curiosity, I added an extra [_session retain] to make it leak so I could follow the malloc history of it in instruments. It was interesting to see some internal things called that were not called in the malloc history of my app.

enter image description here

You can see this has [EAAccessoryInternal removeSession:] called 3 times. This was never called in the malloc history of my app. I think this is key to why my EASession is not being released...

Ageratum answered 23/4, 2012 at 21:22 Comment(4)
Regarding splitting the alloc and init, you might want to read the answers to this question: Why in Objective-C does doing alloc and init in separate statements cause the object to be released according to the Xcode static analyzer?. While possibly unrelated, splitting these two is not recommended for the reasons discussed there.Pless
@BradLarson I appreciate your comment. I'll put them back together and try things out. The EADemo appears to work fine without leaking. It also has retain count of 4 after the alloc and initWithAccessory:forProtocol:, but before releasing the EASession has a retain count of 1... So I'm doing something wrong.Ageratum
I have been seeing this too. Let me know if you found the answer!Dietz
Have you tried to setDelegate and scheduleInRunLoop before stream open?Bader
W
1

I know this discussion is quite old now but I had exactly the same problem recently using ARC e.t.c. I've found that one way around it is by just not closing the input or output streams. Just have a class that deals with all input e.t.c and forward on the data on request to other parts of your application. You can re-alloc init the EASession object with no complaints from XCode so I'm assuming the old EASession is dealloc ed OK as it's no longer referenced by my APP. I haven't checked the leaks yet however.

Writeup answered 16/3, 2014 at 12:18 Comment(0)
W
1

While the demo does it the other way round, I managed to fix this leak by calling the input and output close methods after removing them from the run loop and setting their delegate to nil.

Westminster answered 14/4, 2014 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.