Sunday, November 13, 2011

Choosing a name for your iOS app


As you can imagine, you can't have 2 apps with exactly the same name in the App Store. So grabbing an app name is like grabbing a good domain name. First come first serve. For domain names you probably know that some people registered desirable domains, with no intention to actually use them, only to resell them to the highest bidder. Apple learned something from that, and they try to prevent namejacking. So once you create an app in iTunes Connect, occupying a name, you have a 120 days grace period to submit your app for review. If you fail to do so, the app will be automatically removed from the system and you'll lose the right to use that name ever again under your account.

When that happens you'll get an email from Apple saying that:

You did not upload a binary for your app, ***, during the 120-day grace period. As a result, the app has been deleted from iTunes Connect.
This app cannot be restored, nor can you use the App Name or SKU for any other app under your account in the future.

The same happens when you explicitly delete an app from your account, either before your grace period expires, or if the app is already live.

Deleting it will permanently remove it from iTunes Connect, along with any associated In-App Purchases. The App Name and SKU will not be reusable, even once the app is deleted. 

There are a a few ways to mitigate the risk of losing your app name:

1. Once you grabbed a name, submit the app, any app, perhaps with limited functionality, or even unrelated functionality. Something that Apple would accept in their store. Example apps would be a native wrapper for a web site, PDF publication or a simple app perhaps built off some sample code available from either Apple or 3rd parties. For a competent developer 120 days should be enough to build a version 1.0 of most apps.

2. If you're approaching the end of the grace period, you could try to open a new account, maybe under a different name, of a relative or associate, and move the name to the new account to get a new extension. You'd have to relinquish it from your current account, before it can be registered to the new one.

3. Register the domain matching the app name. That may deter people form trying to use it.

4. Register the name as a trademark. That may give you a legal recourse in claiming ownership with Apple or infringers.

If it comes to worse, and you lose your name, you can still publish your app using variations of that name.

Monday, November 07, 2011

How to deal with "Cannot connect to iTunes Store" errors

Even after I got plenty of experience building apps with in-app purchase capabilities, having gone through the lessons learned at my first attempt, today I was still hit by this error. My purchase attempt on the sandbox would still fail with this laconic message. This is ridiculous. Apple still doesn't provide enough information, or even a small hint of what could be wrong.

Like I mentioned in my post referred to above, you should first check your provisioning profile, to make sure it's bound to a fully qualified app id, not one with a wildcard. In my case it wasn't, even if I should have known better. D'uh ! That's easy to fix, right ? In Xcode I just go in the build settings for the project and set the code signing identity for Debug builds. Any sane person would expect that to be enough. Not so, the build settings for the actual target is still stuck at the old, incorrect, value. That's arguably a bug in Xcode. Why would one have the same setting available in 2 different places is beyond me. Anyway, I had to fix the setting for the target to match that for the project. To my frustration the same "Cannot connect to iTunes Store" failure kept popping.

At that point the only thing I could think of is that Apple's sandbox lost its marbles. So I created a new test account. Tada ! It worked. This is insane. Having to deal with such issues, with deadlines looming, it's the last thing one could wish for. Unfortunately it's not the first time it happens. I had other issues in the past, so ridiculous as having tests accounts used on the sandbox locked, after repeatedly being denied login. After filing a bug report for that lock-out Apple came back with some sort of explanation citing recent changes/"fixes" to the sandbox and prompting me to try again.

I hope my experience could be useful to you if you run into some similar issues. Do you know any other relevant tricks ? If so please comment.

Sunday, November 06, 2011

Adaptive volume level for audio on mobile communication devices

Mobile devices are meant to be used in various environments, as such I find it pretty surprising that the designers of user experience for these devices fail to address one obvious fact: the ambient noise can vary dramatically from one environment to the other. To be fair, each device has a volume control, meant to adjust the level of the audio volume above that of the background noise, however in some cases unexpected bursts of noise may occur in an otherwise quieter environment. It'd be great if the volume would adjust automatically to make up for the increased noise, and later subside when the noise is gone.

The alternative to automatic adjustment is to do it manually, which is the current state of the art. While that's merely a nuisance for regular audio output, like when listening to a podcast, or while in a phone call, it could have more severe effects when applied to the volume of the ring tone. I missed many calls on my mobile phone while I was out on the street, with heavy traffic around me. Even though I have my phone set to both ring and vibrate at the same time, I would still miss calls.

In thinking about solutions to this problem, the obvious approach is to use the microphone, if available on the device, to listen to the environment and react appropriately on increased noise. The drawback of doing such a continuous listening is that it may consume CPU and battery power, and that's probably why it hasn't been considered. Perhaps a better approach would be to let the user decide when that's worth doing. After all, this listening should only happen when audio is playing, so it may not be such a drag on battery.

One could apply further optimizations, by employing location information correlated with past data collected on the same location as a hint for quieter places, or data from the motion sensors as a hint that the user is on the move, hence more prone to the vagaries of the environment.

I remember how my first mobile device, a NEC pager, solved this beautifully. Upon receiving a message, it would first start blinking an LED. If the message was ignored it would start beeping ever so slightly, than it would gradually increase the volume to the point where it was so loud that it was almost painful to hear.

In any case, this should be handled at the level of the platform, since it's a concern that cuts across several apps that produce audio output. I'm looking forward for the first platform that will handle this effectively. My previous experience on Symbian/S60 and my current experience on iOS uncovered this as still lacking. What do you think, have you missed this capability too ?

Saturday, October 08, 2011

How to deal with "A network timeout error occurred. Please try again later." in iTunes Connect

I first encountered this error about a week ago, while trying to set up a new purchase item for an existent app. Given the recommendation to try again later, I assumed it's a transient error and I ignored it.

About a week later I tried again, with the same result:


Hmm, now this doesn't look any more like a transient error, unless a really unlikely coincidence it at play here. In any case I alerted Apple. Then I figured I should also try with a different browser, and sure enough it works fine with Safari.

So if you're getting this too, try switching to Safari and you may be able to work around it.

Saturday, October 01, 2011

Hidden, recurrent costs of developing iOS apps

So you're thinking of building an iOS app for that great idea you have. Awesome ! But if you're not an expert in iOS development you'll need to hire one to build it for you, or maybe you're thinking of using one of those cookie-cutting app makers, that promise "no coding required".

If you want something to stand out from the competition, or if you have some special requirements, your only choice is custom development, with "plenty of coding required". Assuming you're doing it the right way, which will be the subject of a future post, you'll soon figure out that this is going to set you back a certain amount of coin. Just be aware that the sum you're contemplating at that point, based on the quote you got from the developer, is most likely only going to cover the cost of development. Is that all there is ? Well, not really, you'll also need to consider some recurrent, or revolving, costs.

Why recurrent costs ? Well, for one, if you have the app published under your own account, which is probably going to be the case if you're building a custom app, there's the $99 annual membership fee for Apple's Developer Program. Beyond that you'll need to think about the maintenance of the app. What ? Maintenance, like car or building maintenance ? Exactly.

You see, what happens is, these apps are not built in a vacuum, from scratch. Instead they're built on top of an existent platform, the iOS system, which keeps evolving. No doubt you're familiar with the fact that Apple periodically issues updates to the iOS system, indicated by different versions, like iOS 2.1, 3.1, 3.2, 4.2, 4.3, and so on. All these updates add new functionality, and, here's the rub, sometimes change existent functionality. That's right, stuff that used to work in older and current versions of iOS will stop working in future versions.

Why's that ? Two reasons. The first one is controlled. It's called deprecation. As they go along, folks at Apple figure out better ways to accomplish the same thing, or in some cases, the old ways of doing things stands in the way of progress, or conflicts with new planned functionality. In those cases they flag some functionality as deprecated, and provide some alternatives. You're given a period of time, usually unspecified, between several releases, to migrate to the new functionality. That means that for the time being the old functionality still coexists with the new one, but at some point in the future, solely at Apple's discretion, it will go away, and if you didn't migrate, you'll be left hanging.

The other reason is uncontrolled. It's because of bugs and defects that are the usual unintended consequences of changing software code. Every time Apple releases a new version of iOS, that new version has new functionality, fixes for known problems, and new, not yet known, problems. That's the nature of the business.

The biggest changes to the platform, and the most potential for bugs, are when the major version changes. The major version is indicated by the first number in the versioning scheme. For example in version 4.3.5, 4 denotes the major version. When iOS 5.*.* comes about, you'd better watch out.

I've been building iOS apps for a living for more than a year now. Based on that experience I can tell you that if your app has a fair amount of functionality, touching different areas of the platform, chances are high that it will break on the next major release. I had problems both when iOS 4 was released and when iOS 5 got released.

You may ask, how come, since iOS 5 hasn't been released at the time of this post. That leads to the solution. You see, Apple issues beta releases available for developers prior to the official releases. So all you need to do is have your developer proactively test the app on those betas, as they come along, and look for issues. This gives it the "hidden" nature of the cost. You can't know in advance how many problems you'll encounter. So you'll need to budget for that. On my latest project, which took about a year to develop, I had to spend a week to fix problems in iOS 5 beta.

How can one fix those problems ? In some instances they are problems in Apple's code. In those instances the developer must file a bug report with Apple, to let them know about the problem. The developer should next look for possible workarounds, because even if a bug report has been filed, there's no guarantee that Apple will fix it in time for the next release. You can gauge the likelihood of that to happen, by monitoring the incoming betas. The higher the number of the current beta, the closer it's to the GM (gold master) release, after which all bets are off.

In other instances, changes in the platform may rattle some dormant bugs already present in the app. Those bugs are the developer's responsibility. The good thing is that with that responsibility comes power and control too. That is, a competent developer should be able to fix them. That's opposed to the previous scenario, where you're entirely at Apple's mercy, to fix their mess, unless you have a developer that can come up with a workaround. If you work with a less gifted developer, your option is to find a second opinion, or, if the problem hasn't been fixed in time before the release that introduced the breakage, enlist the help from Apple DTS (Developer Technical Support). You get 2 free support incidents per year with your membership in their developer program, and you can purchase more at a low cost. I never had to use that myself, so I couldn't comment more on that.

So there you have it, a rundown of the issues that may crop up post-release. On all my projects I offer my clients a maintenance plan that charges a monthly fee to test the app on the latest beta and to handle any issues encountered. So they can have the piece of mind knowing that their initial investment is protected.



Sunday, September 18, 2011

How to publish your iOS app in the app store if you outsourced its development

Let's say you're a business person with a great idea for an app, yet you have no interest or inclination in doing software development, hence you hand it over to an outsourcing partner. Assuming it all goes well, in due time you'll have a working app that's ready to be published to the world. The development team produces the source code for the app, and possibly some installation package (IPA) that allows you to test it on your device. All looks good and you decide to have the app published under your own account, assuming you enrolled in Apple's iOS Developer Program.

First off, why would you want to use your own account ? It allows you to promote your brand, by showing you as the "Seller" of the app in the app store. It also allows you to directly collect any proceeds from selling the app, or any in-app purchased content, if the app or its content it's not free. In most cases these are strong enough reasons to shell out the required annual membership fee (which at the moment stands at the equivalent of $99 USD). If these don't matter to you, you're better off using the account of your outsourcing partner for publishing.

Assuming you applied and got your membership in Apple's iOS Developer Program you'll have to assist your developer in publishing the app under your own account. Here you can work under 2 possible scenarios:

1. New account

If this is a brand new account, that is, you don't have any existent apps live in the App Store, the best course of action is to hand over to your (trusted) developer the credentials for logging into your account and let them do their thing. This may be stepping beyond the terms of service imposed by Apple, but it's the hassle-free option. You'd cede the access only temporarily, until your app is set up, then you can change the password of the account to take back control.

The alternative workflow, endorsed by Apple, is to add the developer to your account, in a "Developer" role, assuming you have a company account, that is, not an individual account. Company accounts allow having different members under the same account, with different roles. The workflow envisioned by Apple may work well for companies with in-house development expertise, but I found it quite lacking in cases where companies outsource the development as a whole, and have no such expertise (like most of my clients). The reason is that only the person in the "Team Agent" role can submit apps and app updates to Apple for review and inclusion in the App Store. The other members of the account can contribute towards the development of the app, by writing source code, testing, etc, but there's only one person that acts as a gatekeeper for the submission process. By default the Team Agent is the person who applied for the account, who, as a representative of the contracting party, in most cases has no interest or knowledge of the technicalities of building an app. That's why I'd recommend to give your outsourcing partner access to that role.

2. Pre-existent account

This is the case where you have already an account, that was used to publish some other apps, possibly developed by other developers. In that case, besides giving them access to the Team Agent role, you should do one more thing. You see, all apps get digitally signed before they are submitted to Apple for inclusion in the App Store. This signing takes place automatically when the app is being built by the Team Agent and relies on a unique development certificate that must be set up by the Team Agent. If you have ceded that role to a developer, who had that set up for your account, and now you're switching to a new developer, the new developer must have access to that certificate too. When that certificate is set up it produces 2 parts. One is a public part, which is the certificate itself, which encloses a public key. This public part gets stored in Apple's development portal and can be accessed by anyone who has access to the account. The private part gets stored locally on the computer of the person who set up the certificate. If a new person is to use the same certificate for signing purposes she must also get access to that private key. For that you'd need to ask your previous developer to export the private key, as shown in the figure below, and pass it to the new developer.


It's best to ask your developer to give you a copy of the private key, as soon as the certificate gets created, even before you embark on new development projects.

If for some reason you can't receive the key from the previous developer, not all is lost, the new developer in Team Agent role has the option to revoke the old, existent certificate and create a brand new one, with a private key that would be in her control. Although it sounds like a pretty drastic measure, it's really quite benign, as described in Apple's official docs. Your new developer may need to do this anyway if the key passed from the previous developer fails to import properly. I can attest for the effectiveness of the method, as I performed it several times for different clients.


Saturday, September 10, 2011

Reverse-engineering iOS apps through console output and logging

One useful practice in software development is the use of logging, to record details about the status of the app, or other events of interest at runtime. This can be a life saver when problems occur and they need debugging, either live or post-mortem. The logs are also useful during the development of the app, as a way to quickly asses its sanity, at a glance, as opposed to placing breakpoints and using the debugger to inspect the value of variables of interest. In some instances, where timing issues could affect the behaviour of the app, stopping the execution with breakpoints is infeasible, possibly resulting in heisenbugs. In such instances logging can be a better alternative. So you'll find logging used heavily on all types of apps.

In iOS we have this function, part of Foundation framework:


NSLog

Logs an error message to the Apple System Log facility.

void NSLog (
   NSString *format,
   ...
);
Its use is encouraged in many introductory books and tutorials for iOS programming. By default this function outputs content to the device console available through the Organizer view of Xcode. Now, while this is all good for debugging apps that we're developing, I was very surprised to discover output produced by 3rd parties apps, that were installed straight from App Store, in this case "Globe News". I obtained this output by simply running the app on my iPad set up for development, connected to my laptop running Xcode:


In many cases such output may contain sensitive information, like details of various web services endpoints used by the app, or other information that could be used for reverse engineering. This may well be a bug in this particular combination of Xcode/iOS versions, but as developers we need a way to guard against this.

Another concern is the overhead incurred by having our code peppered with such NSLog statements. Each time such a statement is executed, depending on how efficient its internal implementation is, its input parameters may be processed and a string may get formatted, even if there isn't an output sink available. And on mobile devices, like those powered by iOS, where every wasted CPU cycle translates in battery drain, this is of particular concern.

A popular way to control logging is to enable it only in debug builds, by wrapping the calls to logging functions in some macros. For iOS we could use this setup:



#ifdef DEBUG
#    define DLog(...) NSLog(__VA_ARGS__)
#else
#    define DLog(...) /* */
#endif
#define ALog(...) NSLog(__VA_ARGS__)


This snippet can be placed in the _Prefix.pch file, that makes the macro available in all source files. Using this macro enables logging only on debug builds, hence getting rid of all problems mentioned above. Your released app, available in the App Store wouldn't even have any logging compiled in, hence it would be better protected against reverse engineering.

Friday, September 02, 2011

Obvious shortcomings of Apple's App Store

Having published more than 40 apps in the App Store, on behalf of my clients, I'm in a good position to comment on possible ways to improve it.

Perhaps the most glaring omission is the inability to quickly revert to a previous version of an app, once a newer update has been approved and went live. Sometimes mistakes occur, and those mistakes could easily go live.  Based on my experience, once an account has a fair number of apps published (like over 30), and an unblemished history, with few app rejections, it seems that Apple's review process gets noticeable lax (as a better word for sloppy). In one instance an app update was glaringly broken on retina display devices (i.e. iPhone 4), yet it was approved and went live.

In such instances your only recourse is to either pull the app from the store, and/or to prepare and issue a new update, but that has to go back to the waiting queue. This could have terrible business consequences, because there wouldn't be a working app available for about a week. You could try to speed it up, by requesting an expedite review. Although the onus is on the developer to test each update before publishing it, it'd be very helpful to be able to revert to a previous, functioning, version.

A related idea would be to have some sort of a staging area, whereby a new app, or an update of an existent app, could be made available through an obscure URL to a set of testers, after it has been reviewed, but before being made available to the public at large. This may be already supported through the option of manually releasing the app after the review completes, though the fact that there's a single URL that points to the app in the store, irrespective of its version, may suggest that the URL points to the latest live version. This staging area mechanism would be similar to the Ad-Hoc distribution, only more scalable.

Another thing missing is an API to access the App Store functionality programatically. Some apps lend themselves to a cookie cutting model, whereby the same template is used to produce multiple apps, perhaps being differentiated by the content they package and some branding. In such instances the ability to programatically interact with the store would be very useful.


Friday, August 26, 2011

Crash reports fail to symbolicate using xcode 4.0.2

I got some crash reports recently, for some work in progress iOS app that I distributed to my clients via an IPA. To my surprise the reports fail to symbolicate, hence are pretty useless in hunting down the root problem.

I never had this problem before, and its occurrence seemed to coincide with my recent move to using the Xcode 4.0.*. Doing some Googling uncovered a post with a bit of background regarding this issue. It turns out that the newer versions of Xcode changed the way IPAs are built, and in the process broke the symbolication. D'oh !

Now, as a rule, whenever I upgrade stuff I try keeping a copy of the old version, as a precaution. Luckily I have an Xcode 3.2.5 still installed, as a fallback mechanism. All I need is to rebuild my IPAs using the older version of Xcode, until Apple fixes their tools. The post quoted above suggests fixing the Perl script that causes the problem. I'm not sure about that. It may work for a particular version of Xcode, as a last resort, if you really need Xcode 4.0.*. Falling back to Xcode 3.2.* seems a simpler, safer alternative, at least for my needs.

Saturday, July 30, 2011

Google effect in action

I've been running a web site that acts as a wrapper for Amazon's aStore. This was started as an experiment a few years ago, yet it didn't accomplish much, beyond a learning experience in how to use PHP to perform some on-the-fly screen scrapping and content embellishing. It was also something I could use when experimenting with PPC advertising. Having been pulled in some lucrative projects I didn't pay any more attention to this. In fact functionality that used to work, like search engine friendly URLs (SEFU), is now broken...

Anyway, glancing over my analytics account today I see a smashing 338% traffic increase during the last month:


Wow ! All this traffic coming from Google. To what do I owe the honour ? No inbound links, none of the usual favourable auspices. The only logical explanation is Amazon dropping their affiliates form California, about at the same time as my jump in traffic, which likely caused the poor folks to pull the plug on their sites. Or perhaps a glitch in Google's secret sauce for bestowing wealth in cyberspace ? Anyway, the people are coming in, goals as measured by analytics are fulfilled, meaning people are adding stuff to their carts, good times rolling.

Of course the earnings exploded :)


One thing that strikes me is the conversion rate, which at 7.69% stands much higher than industry average (which I believe stands at less than 2%). So yeah, this passive income thingy is not entirely hype. If you can bring people over, the money will follow.

Wednesday, June 29, 2011

phpMyAdmin as a potential security vulnerability

I really like phpMyAdmin. I use it all the time when developing web apps, to configure my databases. There are probably better tools out there, but this fits the bill for me. It allows doing things like adding fields to a table or configuring indexes using a web-based interface, with no need to remember complex SQL syntax. More importantly, by presenting you all options available for an operation it forces you to think through the operation you're about to perform. It also comes bundled in the MAMP tool that I use as an environment for web development on my Mac.

While it's perfectly fine to use phpMyAdmin in a development environment, I don't think it's a good idea to use it on a production server. It makes it easy for an attacker to brute-force their way into your database. What's the use of properly configuring your MySQL server so that it can be accessed only by scripts running on your web server if you're going to provide them a backdoor that can be accessed with a web app ? Probably that's why you won't find this tool available to install with package managers like yum.

You may think you're going to outsmart the attackers and rename the app to a different name, to make it hard to find, which is essentially relying on security by obscurity. If you really go that route I'd recommend you keep the app available on your site only for a short duration, while you're using it, then move it to a folder that's not accessible via the web. And choose a hard to guess name. I once did that and chose to name it "pma" instead of "phpMyAdmin". Going through the server log the other day I found this trail of probes:


[Mon Jun 27 12:25:39 2011] [error] [client 69.164.2.14] File does not exist: /var/www/html/pubpit/phpMyAdmin
[Mon Jun 27 12:25:39 2011] [error] [client 69.164.2.14] File does not exist: /var/www/html/pubpit/phpmyadmin
[Mon Jun 27 12:25:39 2011] [error] [client 69.164.2.14] File does not exist: /var/www/html/pubpit/pma
[Mon Jun 27 12:25:39 2011] [error] [client 69.164.2.14] File does not exist: /var/www/html/pubpit/myadmin
[Mon Jun 27 12:25:40 2011] [error] [client 69.164.2.14] File does not exist: /var/www/html/pubpit/MyAdmin


Luckily by that time I've grown wiser and had that removed long before the attempted attack. So they'll come on knocking, make no mistakes about it.

A better approach to interact with MySQL is using the mysql command prompt tool, that you'd access once you're logged into your server, via a SSH connection. The only thing is that now you need to enter SQL commands. phpMyAdmin comes to the rescue here with its ability to display the equivalent SQL commands that produce the same effect as the command you performed via its web interface. So you can simply copy and paste those commands at the command prompt. So you're running phpMyAdmin in your development environment, copy the SQL commands and paste them into your command prompt tool running on your production server.

Alternatively, you can also use the "Create PHP Code" link to build up a configuration/install script that sets up your application on the web server. You'll find this all the time with off-the-shelf apps, and such a script also helps distributing your app to the users and repeating the installation on many servers. Just one caveat, make sure you remove that script once you're done configuring, or code it in such a way that subsequent invocations wouldn't cause harm. The last thing you want is a wise guy calling that script and bringing your whole database to a clean slate :).

Monday, May 23, 2011

Good books for the Software Engineering field

I used to rely on Amazon bestseller reports every time I approached a new field of study, to find out the books that are vetted by the readers, with their wallets.

I came across a list of Top 100 Software Engineering books, which attempts to find the best books by using a criterion derived form ratings on Amazon, Jolt awards and number of search results in Google. It could make a good reading list.

Friday, May 20, 2011

How to deal with EXC_BAD_ACCESS triggered by _CFAutoreleasePoolPop

Getting crashes due to EXC_BAD_ACCESS errors means that you're trying to access memory through an invalid pointer. While there can be many ways of messing things up like that, a common one in Objective-C is to over-release an object allocated on the heap. That means that the object is released more times than it is retained.

What makes this an insidious problem is that sometimes those crashes happen at random, are not always reproducible, and the stack trace you get doesn't offer clear clues of what portion of the code is at fault. As you can see from the picture below, all code in the stack trace is system code, none in your control:


Sometimes the stack trace is slightly different, here's another one:


The presence of _CFAutoreleasePoolPop in the trace is a strong indication of the fact that an object that's already been deallocated, as a result of over-release, is now attempted to be released again, during the draining of an autorelease pool.

In such cases you should be looking for 2 pieces of information. What's the address of the object being released, its invalid pointer, and where did that pointer come from in the first place, that is, where in your code it was first allocated. Getting to know the variable name in your code that holds that offending pointer, as it appears at the point of allocation, helps tremendously in solving the issue. All you need to do is search in your code where that variable is being used, where it gets released, and so on. Often times you'll find that you're releasing an object that's already autoreleased (it hasn't been created with a call to a method that starts with "alloc" or "new").

You should be able to somehow reproduce the problem, if you can do that, you're good to go. If reproducing the issue is hard, you might want to try placing breakpoints that stop the execution for a while. In some instances that alters the timing of execution in the system and helps reproducing the issue. Sometimes your only recourse is to run the same code repeatedly until it crashes. You can also try running on the simulator and device. Update: I used this method only on simulator. When running on device you'll get an error when running info malloc-history in GDB. If you can only reproduce the crash on a device you'll need to investigate a way of analyzing the allocation logs, which presumably get stored on the device (e.g. malloc: stack logs being written into /private/var/mobile/Applications/DF97FB1F-546A-4B9A-92AB-B6979B4E28A9/tmp/stack-logs.6413.PubPit.index).

Once you can reproduce the crash, the first thing you need to do is set some environment variables to aid in debugging. In the left pane of Xcode, locate the executable group, and double-click the name of the executable for your project:


Choose the "Arguments" tab in the window that opens and set the NSZombieEnabled, NSDebugEnabled, NSAutoreleaseFreedObjectCheckEnabled and MallocStackLoggingNoCompact like so:


Then run your code, if it crashes, look in the debugger console and you should see something like this:


[Session started at 2011-05-20 11:14:57 +0300.]
GNU gdb 6.3.50-20050815 (Apple version gdb-1510) (Wed Sep 22 02:45:02 UTC 2010)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".sharedlibrary apply-load-rules all
Attaching to process 40114.
PubPit(40114) malloc: recording malloc stacks to disk using standard recorder
PubPit(40114) malloc: stack logging compaction turned off; size of log files on disk can increase rapidly
PubPit(40114) malloc: process 40076 no longer exists, stack logs deleted from /tmp/stack-logs.40076.PubPit.p5tTh9.index
PubPit(40114) malloc: stack logs being written into /tmp/stack-logs.40114.PubPit.Vpmlum.index
2011-05-20 11:14:59.890 PubPit[40114:207] *** -[CFDictionary release]: message sent to deallocated instance 0x652e280
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
(gdb) 


The key info here is:
*** -[CFDictionary release]: message sent to deallocated instance 0x652e280

In my case I have an instance of CFDictionary that was initially allocated at address 0x652e280, which now is deallocated once too many times. The question is where did I ever allocate that object. To find that I do:


(gdb) 
(gdb) info malloc-history 0x652e280
Alloc: Block address: 0x0652e280 length: 48
Stack - pthread: 0xa057c540 number of frames: 42
    0: 0x949d617c in malloc_zone_malloc
    1: 0x132080d in _CFRuntimeCreateInstance
    2: 0x132040a in CFBasicHashCreate
    3: 0x1321ebb in __CFDictionaryCreateGeneric
    4: 0x1321bd1 in CFDictionaryCreateMutable
    5: 0x13462ac in parseXMLElement
    6: 0x13469fe in parsePListTag
    7: 0x1345891 in parseXMLElement
    8: 0x1344a94 in _CFPropertyListCreateFromXMLStringError
    9: 0x13435a8 in _CFPropertyListCreateWithData
   10: 0x1399957 in _CFPropertyListCreateFromXMLData
   11: 0xf92ef in +[NSPropertyListSerialization propertyListFromData:mutabilityOption:format:errorDescription:]
   12: 0xfa9c in -[Model loadData] at /Users/bhapca/WORK/Cocoa/Pubpit/Classes/Model.m:171
   13: 0x102b8 in -[Model init] at /Users/bhapca/WORK/Cocoa/Pubpit/Classes/Model.m:251
   14: 0x103fe in +[Model sharedModel] at /Users/bhapca/WORK/Cocoa/Pubpit/Classes/Model.m:268
   15: 0x6c54 in -[PagingViewController loadView] at /Users/bhapca/WORK/Cocoa/Pubpit/Classes/PagingViewController.m:716
   16: 0x4275e3 in -[UIViewController view]
   17: 0x425a57 in -[UIViewController contentScrollView]
   18: 0x436201 in -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:]
   19: 0x434831 in -[UINavigationController _layoutViewController:]
   20: 0x435b4c in -[UINavigationController _startTransition:fromViewController:toViewController:]
   21: 0x430606 in -[UINavigationController _startDeferredTransitionIfNeeded]
   22: 0x548e01 in -[UILayoutContainerView layoutSubviews]
   23: 0xd6c451 in -[CALayer layoutSublayers]
   24: 0xd6c17c in CALayerLayoutIfNeeded
   25: 0xd6537c in _ZN2CA7Context18commit_transactionEPNS_11TransactionE
   26: 0xd650d0 in _ZN2CA11Transaction6commitEv
   27: 0x37c19f in -[UIApplication _reportAppLaunchFinished]
   28: 0x37c659 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:]
   29: 0x386db2 in -[UIApplication handleEvent:withNewEvent:]
   30: 0x37f202 in -[UIApplication sendEvent:]
   31: 0x384732 in _UIApplicationHandleEvent
   32: 0x1cdda36 in PurpleEventCallback
   33: 0x13f2064 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
   34: 0x13526f7 in __CFRunLoopDoSource1
   35: 0x134f983 in __CFRunLoopRun
   36: 0x134f240 in CFRunLoopRunSpecific
   37: 0x134f161 in CFRunLoopRunInMode
   38: 0x37bfa8 in -[UIApplication _run]
   39: 0x38842e in UIApplicationMain
   40: 0x1e74 in main at /Users/bhapca/WORK/Cocoa/Pubpit/main.m:14
   41: 0x1e05 in start
(gdb) 


BINGO ! My code that allocates that object and the variable used to point to that object is in: -[Model loadData] at /Users/bhapca/WORK/Cocoa/Pubpit/Classes/Model.m:171

Now all I need is too look at that code and figure out where that object gets released more than needed.

It's important to remove those NSZombieEnabled, NSDebugEnabled, NSAutoreleaseFreedObjectCheckEnabled and MallocStackLoggingNoCompact environment variables, once you're done with debugging, to prevent them to affect the released version of your app.

Credit goes to this site, where I first learned about MallocStackLoggingNoCompact.

Update: Apparently the same investigation can be performed using the Instruments tool that comes with Xcode 4, by choosing the Zombies trace template. I believe that is the method now recommended by Apple for dealing with this type of issues.

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.

Tuesday, February 15, 2011

how to rebuild PHP on CentOS or other RedHat derivatives

I was faced with the prospect of rebuilding the PHP interpreter on a server, to add support for GD.

Googling for info yielded this article with some good overview of the process.

After I downloaded the sources and started the configure process I was hit with a slew of errors related to the fact that there were missing some dependencies. Stuff like "xml2-config not found. Please check your libxml2 installation."

One cure for that seems to install the development version of those components, like so:

yum install component-devel 


For me googling the error messages pointed me, in order, to the following resources that helped me solve the issues, here, here, here and finally here.

Wednesday, February 09, 2011

how to work around the "Upload Aborted or Timed Out." errors in iTunes Connect

Lately I've been getting this error when trying to upload screen shots of some apps running on iPad.

It seems to happen for large files, over 1MB. One of my apps does magazine publishing, as such if we take shots of the app showing the cover of the magazine, those usually exceeds that limit and the upload fails.

One way to get around that is to save the large PNG files as smaller JPEG files, of lower quality. You can do that using a tool like Gimp. If you go below 1MB the issue disappears.

Wednesday, February 02, 2011

beware of mysqli_stmt_execute clogging your database connection

There are multiple advantages in using prepared statements with MySQL. Improved performance and escaping of parameters passed to queries, to prevent SQL injection attacks come first to mind.

However, you need to be careful with mysqli_stmt_execute, especially if you run queries that produce result sets. If for some reason (e.g. alternate code path taken due to some error) you don't fetch the content of the result set, and if you don't explicitly close the prepared statement, any new queries sent over the database connection associated with the prepared statement that has results pending will fail.

That is, until you fetch the results with mysqli_stmt_fetch, or close the statement with mysqli_stmt_close, you won't be able to reuse the database connection to issue new queries.

This is intuitive enough, albeit a bit surprising, as it behaves very different from the regular mysqli_query that uses non-prepared statements, which is not subject to such constrains.

Monday, January 03, 2011

How to convert m4v files to ogg

I've been experimenting with the video element introduced by HTML 5, in an attempt to replace my current solution that uses Flash.

It soon became evident that the improved performance provided by the native video element came at lack of cross platform compatibility. Videos like m4v files would play nicely on Safari, but wouldn't play on Firefox. Some search on Google led me to http://www.wyodor.net/_Demo/html5/HTML5Video.html, which revealed that Firefox recognizes only video/ogg format.

The next hurdle was how to convert the m4v files to the video ogg format required by Firefox. I found this utility particularly useful for that.