I’m seeing a difference in behavior when creating objects in an Objective-C++ class.
If I create an NSDictionary containing NSNumber objects using dictionaryWith and numberWith, then the objects never get released. If I create them using alloc and initWith, then they get cleaned up just fine.
I’m not seeing this in an Objective-C class in the same project. The project has ARC enabled. I’m using the Allocations profiling tool in Xcode 4.5.2, looking at the “# Living” value of CFNumber and __NSDictionaryl.
// These objects will NOT be released.
NSDictionary* dict1 = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithUnsignedInt:val1], @"val1",
[NSNumber numberWithUnsignedInt:val2], @"val2",
[NSNumber numberWithUnsignedInt:val3], @"val3",
nil];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]
postNotificationName:KEY_NET_STATS_VIEW_UDATE object:nil userInfo:dict1];
});
// These objects *will* be released.
NSDictionary* dict2 = [[NSDictionary alloc] initWithObjectsAndKeys:
[[NSNumber alloc] initWithUnsignedInt:val1], @"val1",
[[NSNumber alloc] initWithUnsignedInt:val2], @"val2",
[[NSNumber alloc] initWithUnsignedInt:val3], @"val3",
nil];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]
postNotificationName:KEY_NET_STATS_VIEW_UDATE object:nil userInfo:dict2];
});
It’s no problem for me to write my code using alloc/initWith but I’d like to understand why the difference. Everything I’ve read says they should be equivalent under ARC.
Stack trace of when this code gets called. All of the below is C++, BTW.
#0 0x001fbbe4 in ItRtpSessionManageriOS::OnItRtpOutgoingStatsUpdate(ItRtpSession&, ItRtpSessionManager::ItRtpStats const&)
#1 0x0007018a in CSceApp::OnItRtpOutgoingStatsUpdate(ItRtpSession&, ItRtpSessionManager::ItRtpStats const&)
#2 0x0006b808 in ItRtpSession::CallStatsUpdateCallback(ItRtpSessionManager::ItRtpStats const&)
#3 0x0006ab1e in ItRtpSessionSharedCommXYZ::UpdateOutgoingStats(unsigned long, unsigned long)
#4 0x0006a958 in ItRtpSessionSharedCommXYZ::Update(unsigned int, unsigned int)
#5 0x000764ca in CSceApp::EvTimerServiceMgrAwaken(bool, unsigned int, void*)
#6 0x00076908 in non-virtual thunk to CSceApp::EvTimerServiceMgrAwaken(bool, unsigned int, void*)
#7 0x002a0134 in xyz::CServicingThread::Activate(unsigned long long, bool*)
#8 0x0029fb98 in xyz::CServicingThread::Behavior()
#9 0x0029fc34 in non-virtual thunk to xyz::CServicingThread::Behavior()
#10 0x002578de in xyz::CAliveObj::StartMechanism(void*)
#11 0x00259f9e in xyz::CThread::ThreadEntry(void*)
#12 0x348b5310 in _pthread_start ()
#13 0x348b51d8 in thread_start ()
Under ARC, there are two mechanisms for utilising autorelease pools – as part of the runloop and tied to scope using @autoreleasepool. The pool is only drained at the end of the runloop, in the first case, or when the autorelease pool goes out of scope, in the second.
So, if you’re not letting the runloop run, anything you put there won’t be drained. Likewise if you’re using @autoreleasepool somewhere but aren’t exiting that scope – perhaps you’re sitting in a tight loop somewhere, or blocking inside the scope – then you won’t see the pool drain.
Given that, you should look at your code to see if that is what’s happening. Unfortunately unless you post more of your code, we won’t be able to help you pinpoint the problem.