So I've been seeing this crash pretty frequently in Crashlytics, both on iPad and iPad 2, running iOS 5. It looks like it's caused by a memory warning, but the stack trace doesn't reference any of my application code, just iOS frameworks:
0 libobjc.A.dylib objc_msgSend + 15
1 UIKit -[UIViewController purgeMemoryForReason:] + 64
2 Foundation __57-[NSNotificationCenter addObserver: selector: name: object:]_block_invoke_0 + 18
3 CoreFoundation ___CFXNotificationPost_block_invoke_0 + 70
4 CoreFoundation _CFXNotificationPost + 1406
5 Foundation -[NSNotificationCenter postNotificationName: object: userInfo:] + 66
6 Foundation -[NSNotificationCenter postNotificationName: object:] + 30
7 UIKit -[UIApplication _performMemoryWarning] + 80
8 UIKit -[UIApplication _receivedMemoryNotification] + 174
9 libdispatch.dylib _dispatch_source_invoke + 516
10 libdispatch.dylib _dispatch_queue_invoke + 50
11 libdispatch.dylib _dispatch_main_queue_callback_4CF + 156
12 CoreFoundation __CFRunLoopRun + 1268
13 CoreFoundation CFRunLoopRunSpecific + 300
14 CoreFoundation CFRunLoopRunInMode + 104
15 GraphicsServices GSEventRunModal + 156
16 UIKit UIApplicationMain + 1090
17 500px iOS main.m line 12
I've googled high and low but can't find any solutions to this. It looks like this is caused by over-releasing a UIViewController instance, but I'm using ARC, so I don't see how that could be the case.
I'm at a loss of how to even approach this. I can't even tell which UIViewController subclass is causing the issue. I've tried reproducing the problem in the simulator and on the device, but I can't find what causes it. Has anyone seen anything like this or have suggestions on how to approach reproducing the issue?
I noticed the exact same stack trace in crashes reported by HockeyApp for devices running on iOS 5.
I never called
[[NSNotificationCenter defaultCenter] removeObserver:self]
except inside dealloc, so this could not be the cause of the crash.Here is how I was able reproduce the crash: from
MasterViewController
I pushDetailViewController
, then pop it by tapping the back button. Finally, I trigger a memory warning and the crash happens (on iOS 5 only).It turns out that the
DetailViewController
instance is not released after being popped because of a retain cycle when using SVPullToRefresh:Since the
DetailViewController
is not released it’s still registered for memory warning notifications and this is what happens:Or in english: the
SVPullToRefreshView
instance is released as a result of the view being unloaded. Since theSVPullToRefreshView
instance is the last object to hold a reference to theDetailViewController
, it is released, then deallocated. ButpurgeMemoryForReason:
was still doing things (i.e. accessing instance variables) with the just deallocated view controller, hence the crash.Once diagnosed the solution was very simple: just avoid the retain cycle in the first place.
I think I've solved the issue. I was thinking about it, and the problem isn't the unloading of the UIViewController view, it's the posting of the actual low memory warning notification. There are several instances in my code where I call
[[NSNotificationCenter defaultCenter] removeObserver:self]
. This is fine in the dealloc method, but there were two instances of this inviewDidUnload
methods.I noticed this when my breakpoint in
didReceiveMemory
of one of the UIViewController's wasn't getting hit. The code inviewDidUnload
was also unregisteringself
from other, system notifications as well, as detailed here.I'm not going to mark this as an accepted answer until I verify that the crashes stop with the new update.
UPDATE: I've verified with Crashlytics that the problem has been fixed!