BuySellAds.com

Read the chapters in my new book Barcodes with iOS 7 as I hand them in. Great new app opportunities await!
Our DNA is written in Objective-C
Jump

Category Archive for ‘Recipes’ rss

Array Self-Sorting

The current Dr. Touch Part that I am working on for my store is about quickly clustering POIs if they would be too close together on a MKMapView. For this purpose I need to calculate distances between all annotation pins and add to this the distances to all newly found clusters. Currently this involves resorting the whole list of distances multiple times. So I put my thinking hat on and built this category extension for NSMutableArray to add numbers of objects in the correct place according to the specified sort order.

To cut down on search time for the insertion point I am using a “divide an conquer” approach. Split the search range in half and check if the value at this index is bigger or smaller than the one I am trying to insert. Continue to divide until the length of my search range is 0. At that point I have found the appropriate place for the insertion.

This approach means that for 1000 values/objects in the array only 10 comparisons are necessary. This is most likely way less than if you are constantly creating sorted copies of the array with one of the three standard sorting methods.

Read more

Easier Version Checking

Sometimes you may need to modify your app’s behavior depending on which OS version it’s running on. As of XCode 3.2 you can choose a different SDK to compile against than you choose for the deployment target. This allows to make an app that runs as low as 2.0, but uses all the bug fixes in the SDKs. And it forces the compiler to make dynamic links to 3.x frameworks. So you can check at run time if such a framework is available and if not present the feature that depends on it.

When working on DTAugmentedRealityController I needed to limit it’s use on devices with a magnetometer and also which run a version of iPhoneOS that’s greater than or equal to 3.1 because this is the version when Apple introduced the capability of overlaying your own view on top of an UIImagePickerController. So I needed an elegant method, I would not settle for comparing strings. That’s why I came up with this extension to UIDevice.

Read more

Adding Last Build Date & Time

If you need or want the date and/or time the last time your app was built then there are two handy macros you can use. Consider the following example:

char *date = __DATE__;  // e.g. 'Dec 15 2009'
char *time = __TIME__;  // e.g. '15:25:56'
 
NSLog(@"Build date: %s", date);
NSLog(@"Build time: %s", time);

I tested it with GCC 4.0, GCC 4.2 and even the new LLVM GCC 4.2. It worked fine with all three compilers.

Those are precompiler macros which work by getting the precompiler to replace them with the current date and time when the file in which they are located in gets built. Bear in mind that generally building is incremental and therefore these will only get updated if there really IS a new build happening. That’s a drawback if you forget it, but you can or should always do a build – clean before you build a release or distribution version to make certain all got updated.

Since those macros date back to C times they get replaced with C-style strings. That’s a pointer to a char array with a binary zero at the end to terminate the string. To convert them to obj-C NSStrings is simple by means of the %s formatter or by using one of the more complicated initializers of NSString.

char *date = __DATE__;
char *time = __TIME__;
 
NSString *myDate = [NSString stringWithCString:date encoding:NSASCIIStringEncoding];
NSString *myTime = [NSString stringWithFormat:@"%s", time];

Finally if you are really so much “pro” that the build time of your app matters, then you will probably also ask if there is a way to force building of certain files to forego the incremental building. Sure you can. All you need to do is to add an extra script to your target to set the last modified time of the file using these macros to the future.

touch -t 2012310000 "${PROJECT_DIR}/Classes/CalendarAppDelegate.m"

Touching Script

It’s not enough to simply set the modified time once because then the next modification sets it back to the current date. Thus the need for this simple unobtrusive script, in this example I am setting the modified time for CalendarAppDelegate.m to Dec 31st 2020 which is sufficiently far away so that this blog article will work for the next 11 years. :-)

How to make a Pull-To-Reload TableView just like Tweetie 2

When I started on Twitter, I tried out a few Twitter clients both on Mac and iPhone until I quickly settled on Tweetie. When Loren Brichter made the bold move to sell Tweetie 2 as a seperate app I also purchased it because I am convinced this guy means quality and Tweetie 2 is on the first page of my springboard.

One thing that’s cool about Tweetie 2 is the fresh paradigm to refreshing the contents of a table view. Up until now we had been looking for space to mount a reload button on, sometimes having to resort to adding an extra tool bar for just one view so that you can have enough space. Now if you have a tableview that it sorted reverse chronologically, then you have a natural urge to make new items appear at the top by pulling down the table with extra force.

Loren recognized this need and innovated the Pull-To-Reload paradigm. If you want to refresh a tableview in Tweetie 2 then you simply pull down the table far enough for an additional cell to appear at the top with the instruction “Pull down to refresh”. If you do, then at a certain point the arrow rotates and the text changes to “Release to refresh”. All accompanied by two distinct wooshing sounds and a pop once the reloading action has ceased. The Intuitiveness of this paradigm is so compelling in fact that people who use Tweetie 2 start to try to refresh ALL tableviews like this.

Might be a good case to make this the standard way from now on because it feels more logical and natural than to tap on a small button with a circular arrow on it. A user of MyAppSales requested that I add this mechanism for reloading reviews of individual apps. At first I thought this to be advanced magic, probably using forbidden techniques. But after a bit of research and lots of hints coming from my Twitter friends (thanks Thomas and Fabian) I figured it out. This article explains how I did it.

Read more

Getting the User's Language

Geppy Parziale¬†wrote about this topic on his “Invasive Code” blog. The method he proposes is to be found in Apple’s documentation and looks like this:

NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];

This is a good method to retrieve the set language, BUT it has two major drawbacks when used in regular apps:

  • Changes are not visible to the app by simply changing the language in settings. It seems you also have to change the region for it to be effective.
  • This really returns the user’s set language but for most cases you instead want to know which localization is used.

What good does it get you if you know that the user has set Klingon as his iPhone language? Not much because most of the time you then still want to know which localization is the currently active one.

You know if the iPhone is set to any language that is not amongst your localizations then the auto-localization feature falls back to the app’s default language, usually English. If you add German localization and the user chooses German then this is automatically used.

I learned this the hard way when we added multiple languages to LuckyWheel. Now here’s the method that I found to be way more useful:

NSString *selectedLocale = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];

If you read Apple’s page to the end you get to a box where it says:

“Although you can get the user’s preferred settings from the defaults database, it is recommended you use the CFBundleRef functions or NSBundle class instead. The associated functions and methods of those objects return the preferred language or locale that is also supported by your application.”

That’s exactly what I am saying …

UIImage from UIView

This is a neat trick that I developed when I needed a PNG Image with the same content that I was already drawing in a UIView. I had finished the broad strokes of a small app I am developing and then I figured it would be a neat trick to also be able to e-mail a graphic I was drawing as an attached image.

Turns out to be not that hard to do – after a couple of hours of trial and error. Though attaching said PNG file to an e-mail is only something that’s available with SDK 3.0 and above. But that’s another story, let’s stick to the image generation technique I developed. And one more thing: I am NOT taking about the contents of subviews to be put into an image, strictly what’s the result of the UIView’s drawRect method.

Read more

Manipulating UIColors

For the charting class I am working on I wanted to modify a given UIColor by darkening it and also by making it more translucent. This is both straightforward for some aspects but also tricky for others as I have learned.

Looking at the documentation for UIColor you find that there are only several methods provided of creating a UIColor, but none to actually modify it. Neither you will find any colorByModifying… methods, nor is there a UIMutableColor class true to the general rule of keeping mutable and immutable variants for all the important classes.

If you do a bit of Quartz drawing then you also know about CGColor, CG being short for CoreGraphics. Here we have more luck. Actually UIColor is basically a wrapper for a CGColor as I have learned subsequently. By using CoreGraphics functions to modify this internal CG color I was able to come up with two category methods extending UIColor with the missing functionality.

Read more

Deep-Copying Dictionaries

Cocoa Touch has this concept of basic functionality being immutable and then there is a bigger brother of most classes that adds mutability. One effect of this pradadigm is that often you reuse a single NSString throughout your code because you pass around a pointer to it, retaining it wherever you are interested in it’s continued existence in memory.

Only very rarely you would see the use of the [receiver copy] approach which is like an init but creates a copy of the object. As I said this rarely makes sense because if the original is non-mutable in the first place why do I need to clone it? If it is used in another place and then there it is released and some other static value retained it does not have any adverse effect on other places where it is used, provided that proper retaining occurs.

But this feature is there because there might really BE some esotheric cases. There is even the “copy” attribute for properties which sets up your setters to copy the incoming objects, as opposed to the “retain” attribute which simply retains it.

Read more

Developing iPhone Apps on Snow Leopard

I was quite looking forward to getting a chance to improve my already quite satisfying Mac experience to the latest iteration of the operating system. Having bought my new MacBook Pro after Juni, I was elegible for an extra cheap upgrade. So I filled in my serial number and got promised a delivery about a week afterwards. But not being the patient type I figured it would not be a sin to borrow a friend’s DVD and install the new cat. Hey, I own a license, who cares which media I’m using?

Installation was as painless as can be. You pop in the DVD while your Mac is running, click a couple of times and then you wait. After 20% there is a first reboot, then you wait, all together roughly 40 minutes. At first you don’t see any new stuff, except the same welcome Animation playing in a Window instead of full screen. But then you start to see little things. Many little things, in fact enough to warrant a 23-page in- depth technical review on Ars Technica which is great bedside reading making you dream nicely about your invigorated Mac.

I was excited to install the new Xcode 3.2 from the “Optional Installs” folder on the DVD, then I downloaded and installed the latest iPhone 3.1 SDK for Snow Leopard which in contrast to Leopard is just the SDKs and now Xcode. The Leopard version contains Xcode 3.1.4, which for strange reasons does kind of run, but is “not officially supported by Apple to run on Snow Leopard”. Still, I will show you how you CAN compile against a 2.x SDK. After that I will show you Apple really wants you to do, but leaves it up to SDK diggers to tell the public.

Read more

Love to be Notified!

One of the techniques which I have found to be extremely useful are notifications in Objective-C. Using NSNotification to send broadcasts to all objects in your app is something that I did not see in any other language or framework I visited before. Here is a quick recipe to show how to use them.

Think of notifications as a method of informing all your class instances within your app at the same time. Sometimes there is a global change that does not have a single target like you would for a delegate. Without notifications you would have to keep track of all objects to be informed of the change manually, loop through them and call an update method.

To give one useful example: In MyAppSales you can set your main currency so that all amounts get converted into the currency you are used to instead of showing you Japanese Yen. Now what happens if the user chooses a different currency and you have objects like table views, table cells or your own class instances that need to change something whenever the main currency changes. Enter NSNotification and NSNotificationCenter.

Read more