One of the biggest pains (besides Objective-C itself) is definitely the memory management on the iPhone. Luckily we don't have this problems on Android, due to the fact of using Java and garbage collection, which makes programming an ease (almost!) and enables you to focus on creating something rather than wasting a lot of time debugging. However, Apple decided not to include garbage collection for the iPhone, even though it's available within their frameworks and is actually used for Mac development. I won't elaborate much more on the pros and cons of Objective-C's memory management and the object ownership concept, since a lot of other bloggers ranted about that topic already too many times before me, but rather give you some useful tips to reduce the time you spend debugging.
The most common problem you will have is probably an EXC_BAD_ACCESS error, which occurs when you try to release memory that has already been released. This could be the reason if for example you try
- to release an object, which you don't own
- to release an object, which is in the autorelease pool
- to release an object, which has the "assign" property instead of "retain"
You might, for example, get an output like this:
2010-03-07 15:03:11.136 MyProject[58016:207] *** -[UIView setFrame:]: message sent to deallocated instance 0x1b33240Finding the source of that problem is hard by just knowing the object's address in memory: 0x1b33240. Thus we should enable a few options in our executable's settings: under group & files doubleclick on your executable and then under the "Arguments" tab add and enable the following options:
Program received signal: “EXC_BAD_ACCESS”.
NSDebugEnabled
MallocStackLogging
NSZombieEnabled
MallocStackLoggingNoCompact
Now recompile your code, run it in the simulator and try to reproduce the same error you had before. But this time you will be able to enter the following command in gdb:
shell malloc_history $PID $ADDRESS_OF_OBJECT_IN_MEMORYIn our case that would be (see the pid and address I marked red above):
shell malloc_history 58016 0x1b33240and results with the following (or similar) output:
ALLOC 0x1b33240-0x1b33267 [size=40]: thread_a02fa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _reportAppLaunchFinished] | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerLayoutIfNeeded | -[CALayer layoutSublayers] | -[UILayoutContainerView layoutSubviews] | -[UINavigationController _startDeferredTransitionIfNeeded] | -[UINavigationController _startTransition:fromViewController:toViewController:] | -[UINavigationController _layoutViewController:] | -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] | -[UIViewController contentScrollView] | -[UIViewController view] | -[CategorySuperViewController loadView] | -[CategoryViewController initWithStyle:] | -[Functionality requestNewAd] | +[AdMobView requestAdWithDelegate:] | +[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance | _internal_class_createInstanceFromZone | calloc | malloc_zone_callocWhat we can see is where exactly the error occurs, but we still don't know by what it is caused and where this happens in the code. What we know though, is that it has something to do with an AdMobView object, which we most likely released at some other point in our code where we shouldn't have released it (because we didn't have ownership or because it's on autorelease).
To fix the problem we just check all AdMobView releases. If you're unsure you can just temporarily disable them, recompile and run it again to see if that was the problem. Another thing, that happens to me sometimes, is that I accidentally type dealloc instead of release, which immediately removes the object from memory, while with a release it might keep existing, because it may still be owned by someone else. In general, never use dealloc (unless you really know what you're doing).
I hope this helps you to make iPhone development and debugging a bit easier and please let me know if something is still unclear.
I've just launched a new side project of mine:
Bugfender - A modern remote logger tailor-made for mobile development
It's currently free and you can sign up here: https://app.bugfender.com/signup
Any kind of feedback is more than appreciated :-)
Thanks you for this sentence: "Another thing, that happens to me sometimes, is that I accidentally type dealloc instead of release". Thanks a million times over. Thanks[0], Thanks[1], ... Thanks[999999]
ReplyDelete