views:

66

answers:

2

Hi,

I have three layers, the bottom layer is written in C++ and the other two middle and top layers are both in Objective-C.

The C++ layer stores a reference to a class in the middle layer, and the middle layer also stores a reference to a class in the top layer.

Upon receiving a request from the middle layer, the bottom layer is responsible for asynchronously call a method in the middle layer which in turns call a method in the top layer.

Unfortunately, my code reports errors like:

* _NSAutoreleaseNoPool(): Object 0x523e50 of class NSCFNumber autoreleased with no pool in place - just leaking Stack: (0x95c83f0f 0x95b90442 0x28d3 0x2d42 0x95b96e0d 0x95b969b4 0x93a00155 0x93a00012)

The problem is that the method in the top layer was called from a C++ POSIX thread which has no autorelease pool. The only solution I could come up is add the following in the middle layer:

bool temp = false;

- (void) method ...
{
  if (!temp)
  {
    temp = true;
    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];    
  }

  call_to_the_top_layer();
}

This works. My question is that would there be any other better solution? This is ugly...

+1  A: 

As far as I understood your question, you have the bottom layer in a thread which calls the middle layer. As you already discovered you have to have an autorelease pool if you want to use the Cocoa framework (it's not about Objective-C ;)).

You should either create one at thread creation or create and release one for every request to middle layer. Your “solution” does create one on demand which lives until the end of the thread's days

Which one is best depends on your architecture:

  • How long is the thread living?
  • Is it okay to have only a single autorelease pool for it's whole life?

Update:

When you release the temporary pool, you should be aware of exceptions if they may occur:

id pool = [[NSAutoreleasePool alloc] init];
@try {
    …
} @finally {
    [pool release];
}

If you do not have/use Objective-C exceptions DarkDust's answer is the correct way.

Tilo Prütz
The thread lives as long as the application is there. Creating on demand worked, however I am not sure how to release the pool.
Kinderchocolate
You release the pool with `[pool release]` :). Just like in DarkDust's answer.
Tilo Prütz
@Kinderchocolate: if your thread lasts as long as the application, creating an autorelease pool and then not releasing it or even just releasing it when the thread ends is exactly the same as not having an autorelease pool at all. You need to create and release pools more frequently so that memory used by autoreleased objects is recycled.
JeremyP
+2  A: 

Just always allocate a autorelease pool, no problem with that. But you also need to release the pool, otherwise you have a memory leak:

- (void) method
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  // start doing some work, for example:
  call_to_the_top_layer();

  [pool release];
}

You can always create pools, but must release it in the same block. Normally you don't need to do it, except when you create a new thread or sometimes in loops that allocate a lot of temporary values to avoid having too much garbage pile up and fill the memory.

DarkDust
This works. Thanks.
Kinderchocolate