Archive for January, 2009

imageNamed is evil

So a little while back we wrote about the confusing crashes on the device that we eventually figured out were caused by [UIImage imageNamed:] running out of memory when it tried to cache lots of big images. So we apparently solved the problem by making a thumbnail-sized image set and caching those, some 2.9 meg worth, whilst loading in the full sized ones uncached and only as needed.

Well, apparently turned out to be not good enough. See, it’s a few days later and we’ve finalized the design and got everything implemented and all seems to be good … except that it gets terminated without warning sooner or later. And quite often, Springboard terminates as well. Absolutely no correlation to any action or sequence in the program, no leaks, no out of bounds memory accesses, memory usage of the program barely a pittance. Yet, somehow, look at the console and you see system memory warnings scrolling by, you see it quitting background processes, and eventually quitting Springboard and/or the active application. Whilst that active application hums merrily along in blithe ignorance of the system crashing to the ground behind its back.

So apparently not only is 2.9 meg of images cached with +imageNamed enough to bring the iPhone OS to its knees, it’s not smart enough to, you know, actually do anything about it, like oh I don’t know, empty the cache or something?

It’s not like this is hard or anything, you can replicate the caching functionality precisely by declaring yourself an  NSMutableDictionary *thumbnailCache and populating it like

- (UIImage*)thumbnailImage:(NSString*)fileName
{
   UIImage *thumbnail = [thumbnailCache objectForKey:fileName];

   if (nil == thumbnail)
   {
      NSString *thumbnailFile = [NSString stringWithFormat:@"%@/thumbnails/%@.jpg", [[NSBundle mainBundle] resourcePath], fileName];
      thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile];
      [thumbnailCache setObject:thumbnail forKey:fileName];
   }
   return thumbnail;
}

and if you do get a low memory issue, just [thumbnailCache removeAllObjects] and you’re good. But you know what? After replacing the various +imageNamed calls with this … not a single quibble anywhere, the whole 2.9 meg worth of cached thumbnails go right in there and not a single problem for, literally, hours.

(Not that there were any problems after those hours, we hasten to add; simply that, you know, if you think about it, there probably really isn’t a lot of point extending testing of an iPhone application much past the lifespan of a full battery charge…)

So the moral of the story is: DO NOT USE [UIImage imageNamed] for any significant amount of images. It is EVIL. It WILL bring down your application and/or Springboard, even when your application is putting along using just barely a nibble of memory on its own. Take the handful of lines above and implement your own cache!

Continue Reading →
84

New FAQ site

There’s a new site up with the aim of becoming the goto iPhone development FAQ. Eponymously enough, it’s called

http://www.iphonedevelopmentfaq.com/

Nothing too striking there as of yet, but hey, worth a bookmark no doubt.

Continue Reading →
0

Winning the App Store

Now, you may be aware that the multiple-week #1 app in the App Store is called iFart

There are now 26 Fart Sounds included with iFart and the ability to record your own farts.

New Fart Sounds include:

  • Bombardier
  • Brown Mosquito
  • Burrito Maximo
  • Laundry Day
  • Predator
  • Dirty Raoul
  • Silent But Deadly

Using the fart a friend feature you can email the system farts to your friends along with a personal message.

With the Record-A-Fart feature you can record sounds and use Sneak Attack and Security Fart feature with them.

My, my. How could one resist, indeed? But what you may not be aware of is just how … we hesitate to use the word “insanely”, but a better one escapes us … how insanely profitable it is.

After hitting 13274 units on 12/22, a number of stories broke out sharing that our iFart app had net us approximately $10K for that single day…

12/23 was similar to the previous day. We sold 13,349 units.

I was pleased. I’ll take that on any day.

But I had a hunch that Christmas Eve and Christmas Day would be higher. How much higher was anyone’s guess.

All I knew was that a lot of people would be getting iPhones and iPod Touch MP3 players on Christmas Day.

Christmas came a day early for us. On 12/24, my jaw hit the floor when I checked my stats.

We sold 19520 units, providing $13364 in net income after Apple takes their cut.

I now knew that Christmas Day would be bigger than I would have imagined.

I made sure I was sitting down before I checked my day-after-Christmas stats.

It was a good thing.

On Christmas Day, 38,927 people purchased iFart Mobile.

Thirty-eight thousand nine-hundred and twenty seven.

Wow.

Thats $27,249 net.

Again I say, wow.

Yes. Yes, “wow” is an appropriate response.

Here’s another link with the sales graphed up to Christmas.

It’s truly amazing what a little media attention will do for your sales, isn’t it now? And people thought that the gold rush was over. Apparently all you have to do is hit the right note, so to speak…

Continue Reading →
0

Library: Plausible ActorKit

Here’s a useful library for you to be aware of for your concurrent OS X and iPhone programming: Plausible ActorKit, which aims to make interthread messaging easily manageable from any Objective-C object.

The purpose of ActorKit is to facilitate the implementation of concurrent software on both the desktop (Mac OS X) and embedded devices (iPhone OS). On the iPhone, thread-based concurrency is a critical tool in achieving high interface responsiveness while implementing long-running and potentially computationally expensive background processing. On Mac OS X, thread-based concurrency opens the door to leveraging the power of increasingly prevalent multi-core desktop computers.

To this end, ActorKit endeavours to provide easily understandable invariants for concurrent software:

  • All threads are actors.
  • Any actor may create additional actors.
  • Any actor may asynchronously deliver a message to another actor.
  • An actor may synchronously wait for message delivery from another actor.

As an actor may only synchronously receive messages, no additional concurrency primitives are required, such as mutexes or condition variables.

Building on this base concurrency model, ActorKit provides facilities for proxying Objective-C method invocations between threads, providing direct, transparent, synchronous and asynchronous execution of Objective-C methods on actor threads.

The source is available free and MIT-licensed from Google Code; current (beta 2) documentation can be found here. If a project we’re looking at that involves some very complicated Windows RPC code actually gets started, you’ll be hearing more from us on how well this library works in practice! 

h/t: iPhoneSDK!

Continue Reading →
1

Snippet: UIImage alterations

While UIImage is very convenient to work with, it’s short on — okay, entirely absent of — methods to manipulate the underlying image. In general applying a transform to a view suffices for display purposes, but if you want to change the underlying image, you’re out of luck. Unless, that is, you continue reading; for today we’d like to point you to a convenient code snippet , scaleAndRotateImage:

The problems:

  • UIImage provides no easy way to scale, rotate or transform the underlying CGImage.  While it is easy to transform it by placing the image in a view, if you need the actual image changed then good luck.
  • UIImageJPEGRepresentation(), the easiest (only?) way to convert a UIImage to a JPEG uses the underlying CGImage, and ignores your UIImage imageOrientation, so regardless of camera position when the picture was taken the exported JPEG will always be oriented in landscape or right mode, ending up with pictures that need rotation.

The solution:  Thanks to some help in the Apple Support forums, and the #iphonedev IRC chat groups, I was able to clean up a function that takes a UIImage, and fixes it’s underlying core image.

So hey, if you have a reason to scale, rotate, or mirror a UIImage … there you go!

Continue Reading →
4

Extracting SDK icons

So as you’ve probably know already if you’ve tried to customize UITabBarItems, the images you provide are used only to extract the alpha channel. That makes usual stock art not the most applicable, and if you’re as artistically challenged as trolls, you’re not too interested in trying to figure out how to draw that kind of thing yourself.

So the immediate idea is, no doubt, let’s use some of the icons of that type already present in the SDK. Besides saving us trouble, that contributes to a cohesive user experience, and who couldn’t be in favor of that? For example, let’s decide we would like to have a camera image on one of our tabs. So we dig through the simulator resources, which are found at

/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.0.sdk/System/Library

and we find one that looks like what we want, inside the above at

/PrivateFrameworks/PhotoLibrary.framework/CameraIcon.png 

But wait, it’s not quite that easy! All the allegedly PNG images in the simulator SDK are actually in Apple’s wacky iPhone variation of the PNG format, so we have to deal with that somehow. As it happens, some extra friendly fellow has put up an online converter to do so for us. That produces a standard PNG file that we can simply toss into our project, set in Interface Builder … and hey presto,
tabbar
a standards-consistent UITabBar!
[UPDATE: Or, on the other hand, using a camera icon for a camera-related function could actually in Apple's eyes turn out to be a big bundle of FAIL. So be careful with how you use these icons, kids!]
Continue Reading →
7

Image memory

So our latest project — essentially an image viewer for a largish set of static images — which ran fine in the simulator, was in fairly short order throwing up memory warnings and then freezing on the device. Hmmm. That’s bad. So we resolved it, and our process might be useful for you too.

First off, we went to Run/Start With Performance Tool/Leaks in Xcode, to run it under Instruments. That didn’t produce any evident problems with allocation or release of objects. Hmmm, hmmm.

Next, we tried running it under the LLVM/Clang Static Analyzer. (If you haven’t heard of it before, there’s a couple good introductions here and here.) But wait, you say, that doesn’t work for iPhone development? Ah, but indeed it does! What it doesn’t work for is analyzing ARM binaries, so it’s not helpful for device builds no … but the simulator uses Intel binaries! Convenient, yes? Thanks to this post for explaining to us

My workflow after I’ve really worked on the codebase is now:

  • Make sure the project default settings are “debug” and “simulator”
  • Close Xcode
  • open a terminal window and “cd” to the project directory
  • run rm -rf /tmp/scan-build*
  • run rm -rf build/;scan-build --view xcodebuild
  • Open Xcode and fix errors

That’s been working great for me ever since.

Excellent, excellent. This’ll sort us right out! So we ran it … and it came up with exactly one “bug”, an apparent dead store which is actually completely intentional, it’s just that our “check” macro confuses it.

   BOOL wroteOK = [self.favoritesList writeToFile:[self favoritesPath] atomically:NO];

   check(wroteOK);

Righty-ho. Well, it’s all well and good that our entire application is indeed completely bug free to all appearances, pat pat, but that leaves us with an invisible problem. Oh, those are the best kind.

So back to Instruments and the ObjectAlloc tool we went to look for some hints. And it turns out that, despite our code being completely impeccable as far as we thought, newly loaded images were never getting released. As our image folder “pictures” is 70.4 MB, the problem is evident.

The culprit, it turns out, is loading images with [UIimage imageNamed:] which not only caches all images it loads for future use, but is widely regarded as being overly aggressive in its caching behavior. The recommended solution is to use [UIImage imageWithContentsOfFile:] to load your images, which does not cache anything. Good, good … except then the scrolling performance in the image selection gallery list was awful, pokey and jittery. Yuck!

Sooooooo, what we ended up doing was creating a new folder “thumbnails” with list-cell-sized versions of the images, which worked out to 2.9 MB total, a manageably cacheable amount it appears, and loading those with +imageNamed, then using +imageWithContentsOfFile to bring up larger sizes of individual images as selected with no caching. That makes the selection interface nice and smooth again, and the application not break. Success!

[UPDATE: Oh, the fetching naïveté. Isn't it cute? Turns out that +imageNamed is MUCH MORE EVIL than was believed at this point. Executive summary of update link: Do your own caching for any nontrivial amount of images.]

Continue Reading →
8

More review scraping

Happy New Year, all! Looking forward to 2009? We expect it’s going to be … interesting.

To start you off the year with some handy review scraping, here’s a handy little webpage to retrieve all the country reviews for an App Store application, by either application ID or store URL. Based on the same code that we mentioned before that you could work with yourself or install a Dashboard widget to make more convenient, but it’s most convenient of all to bookmark this and pull it up from anywhere, yes?

Continue Reading →
0
Page 2 of 2 12