C++ and Objective-C autorelease problem
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: (0x9开发者_如何学Go5c83f0f 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...
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.
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.
精彩评论