Wednesday, April 27, 2011

When things blow up in Objective-C with a stack trace like "objc_msgSend ??"

I got an "Program received signal:  “EXC_BAD_ACCESS”." error after a small change I made to some code:

NSLog(@"downloadModel from %@, modelPlistUrl");

As you can see, the format descriptor passed to NSLog was expecting to be followed by an NSObject parameter and I failed to provide one. The result is unforgiving:


The call stack appears to have been corrupted, leaving very little to aid in debugging the issue. Here's where it pays to test often, after small changes and to use SCM, that would allow you to see recent changes and hopefully find the problem.

It's pretty disappointing that NSLog fails so badly. According to the docs, %@ placeholders in the format specifier string are meant to be filled with the content returned by "descriptionWithLocale: if available, or description otherwise. Also works with CFTypeRef objects, returning the result of the CFCopyDescription function". So the runtime obviously takes whatever happens to be on the stack frame where the expected parameter should have been and it manages to trash the stack in the process.

I would have thought that the static analyzer invoked with "Build and Analyze" would catch it, but it doesn't either. So your best bet is to code in small increments, test often and use your intuition when cornered.

Monday, April 11, 2011

Possible cause for empty response.products passed to productsRequest:didReceiveResponse: when using Apple's StoreKit

Some time has passed since I first blogged about my first experience with Apple's in app purchase mechanism for iOS, and the pitfalls I encountered.

Since then, I published several apps in the App Store, and now, when the time to update some of them has come, I came across a new issue. When testing the updates to my apps, I'm getting an empty response.products passed to - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response.

It's like Apple's servers doen't recognize my product ids. The same ids that are functioning properly on a live version of the app. WTF ?

Looking more closely on the issue reveals that I've been trying to install my update, built using a dev certificate, on top of the existent version of the app available in the app store, which of course was built with a different certificate. In any case, the ids placed in the request sent to Apple's servers are clearly legitimate. In fact, if I uninstall the app from my device and re-install the app update from scratch everything works fine. This can be used as a workaround for the issue.

This is more likely a bug on Apple's side, although one could argue that the issue is with my code, that perhaps botches the update process. I'll need to run some more tests to rule this out, but in the meantime, if you're having such issues you can try the workaround described above.