PIXEL
DOCK

I like the smell of Swift in the morning…

Build an ad hoc distribution .ipa file for a project that includes static libraries (e.g. Open Ears)

Posted: | Author: | Filed under: iOS, Xcode | Tags: | No Comments »

When I wanted to generate an .ipa file for my latest project I ran into the following problem: my project uses the Open Ears library for speech recognition. Open Ears is included as a static library. When I tried to archive the app to share it with others I could not create the .ipa file. After clicking on “share” the option to save it as an .ipa file was grayed out with the message “No Packager exists for the type of archive”. So no chance to build the necessary .ipa file that is needed for ad hoc distribution.

The solution for this problem is quite simple but it took me some time to find it. The problem is that you have to make sure that the static libraries are included in the application binary. You achieve this by setting the “Skip Install” build setting to “YES” for the libraries: Right click on the library project icon (the blue one) and find the “Skip Install” property in the “Deployment category” in the build settings. Set it to “YES”.

Important: leave the “Skip Install” property of your main project at “NO”.

When you archive your project now, it should offer the save as .ipa option in the share section.

UIColor+colorWithHex: a category to get an UIColor from a hexadecimal integer value or string

Posted: | Author: | Filed under: iOS, Objective-C | 5 Comments »

I always find it really cumbersome to instantiate an UIColor object from a hexadecimal color value. To make life a bit easier I wrote this category for the UIColor class:

@interface UIColor (ColorWithHex) 

+(UIColor*)colorWithHexValue:(uint)hexValue andAlpha:(float)alpha;
+(UIColor*)colorWithHexString:(NSString *)hexString andAlpha:(float)alpha;

@end

@implementation UIColor (ColorWithHex)

+(UIColor*)colorWithHexValue:(uint)hexValue andAlpha:(float)alpha {
    return [UIColor  
                colorWithRed:((float)((hexValue & 0xFF0000) >> 16))/255.0 
                green:((float)((hexValue & 0xFF00) >> 8))/255.0 
                blue:((float)(hexValue & 0xFF))/255.0 
                alpha:alpha];
}

+(UIColor*)colorWithHexString:(NSString*)hexString andAlpha:(float)alpha {
    UIColor *col;
    hexString = [hexString stringByReplacingOccurrencesOfString:@"#" 
                           withString:@"0x"];
    uint hexValue;
    if ([[NSScanner scannerWithString:hexString] scanHexInt:&hexValue]) {
        col = [self colorWithHexValue:hexValue andAlpha:alpha];
    } else {
        // invalid hex string         
        col = [self blackColor];
    }
    return col;
}

@end

Because I often need to convert a hex string (e.g. from a parsed XML file) to an UIColor I added 2 methods to this category. You can now get an UIColor from a hexadecimal uint value or an NSString that can have the 3 following formats: “0xFFFFFF“, “#FFFFFF” or “FFFFFF“.

Just add this category to your project and you can use it like this:

UIColor *col1 = [UIColor colorWithHexValue:0xFFFFFF andAlpha:1.0];
UIColor *col2 = [UIColor colorWithHexString:@"0xFFFFFF" andAlpha:1.0];

You can download the category here.

Feel free to use it.

NSURLConnection: How to avoid blocked file loading during scrolling of UIScrollView or UITableView

Posted: | Author: | Filed under: iOS | Tags: , , | 10 Comments »

When you want to load a file (like a large image) into your app, you don’t want to block the user interface during the loading. It’s always a good idea to load large files asynchronously.

The easiest way to load a file in the background is via NSURLConnection.

NSURLConnection *connection = [[NSURLConnection alloc] 
     initWithRequest:request delegate:self startImmediately:NO];
[connection start];

However, if you use the default settings the connection object will be scheduled in the NSDefaultRunLoopMode. That means that the connection is only executing the request when the app’s run loop is in NSDefaultRunLoopMode.

Now, when a user touches the screen (e.g. to scroll a UIScrollView) the run loop’s mode will be switched to NSEventTrackingRunLoopMode. And now, that the run loop is not in NSDefaultRunMode anymore, the connection will not execute. The ugly effect of that is, that the download is blocked whenever the user touches the screen. And that can be a looong time when the user is scrolling a UITableView, because the download is stopped until the scrolling completely stops. And when the user continues to scroll, the download is blocked again.

Fortunately the solution to this problem is quite simple: You can schedule the connection in another NSRunLoopMode. When you schedule the connection in NSRunLoopCommonModes it will execute in all run loop modes (that have been declared as a member of the set of “common” modes, to be precise). That means that the connection is not only working in NSDefaultRunLoopMode but also in NSEventTrackingRunLoopMode (when the user touches the screen).

[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] 
     forMode:NSRunLoopCommonModes];

Bingo! The async file loading is not blocked anymore during user interaction.

Xcode: Dividing long NSString constants over multiple lines

Posted: | Author: | Filed under: Objective-C, Xcode | Tags: | No Comments »

Just a little Objective-C “trick” to make long NSString constants a little bit more readable in your Code:

To break a part of the long string to a new line you have to wrap it in quotation marks. The compiler will then put it back together to one long string.

So instead of doing this:

NSString *htmlStr = @"PageTitle

Hello World

";

You could do this:

NSString *htmlStr = @""
                       ""
                          "PageTitle"
                       ""
                       ""
                          "

Hello World

" "" "";

Of course the cleanest thing to do would be to separate the html code completely from your Objective-C code by putting it into a separate HTML file and load that into a string. But hey, who wants to be perferct all the time?

NSXMLParserErrorDomain error 5

Posted: | Author: | Filed under: iOS | Tags: , | No Comments »

Trying to parse an XML file I came across this error message. According to the error message the parser could not parse the XML file so I suspected that my XML was malformed. But it wasn’t.

It turned out the problem was that I used the wrong method to load the XML file.

Instead of using:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"demo.xml" ofType:nil];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath]];

I tried to do this:

NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"demo.xml"]];

So the problem was that the Parser could not really load the XML. Strangely enough the parser loaded something because otherwise the parser’s init method should have returned nil. But whatever the parser loaded, it surely was not the right stuff. So be sure to get the XML file’s path from the main bundle and feed that to the parser’s init method.

UIFont: Problem when using more than 2 custom fonts of the same Font Family.

Posted: | Author: | Filed under: iOS | Tags: , | 4 Comments »

When you add custom fonts to your iPhone or iPad App you might experience the following problem: If you add more than 2 font variants of the same font family (e.g. “Normal”, “Bold” and “Extended”), only the last two font variants that you added to the project will be usable. The first variant (the one on top of your list) just won’t show up and is replaced by one of the two variants that were added last to the project.

The reason is quite simple: The iOS SDK apparently allows only 2 custom fonts of the same font family!

As a solution you could change the font-family of your font, so that not more than two font variants have the same font-family. Just to be clear: it’s not enough to change the file name of your font. You have to change all the references to the font-family inside your font files.

You can do this with with fontforge. Fontforge requires that you installed the X11 server on your system, but that should not be a problem as it is automatically installed when you install Xcode.

Make sure that you find all references to the font family name after you opened the font in Fontforge:

  1. Open your Font in Fontforge
  2. Goto ‘Element’ -> ‘Font Info’ and change the ‘Family Name’ field
  3. Goto ‘Element’ -> ‘TTF Names’ and change the fields ‘Family’ and ‘Preferred Family’
  4. Goto ‘File’ -> ‘Generate Fonts’ and save your edited font

With this little trick you should be able to use more than two variants of one font.

cocos2d: unofficial installer solves installation problems

Posted: | Author: | Filed under: cocos2d, iOS | Tags: , | No Comments »

When installing the cocos2d framework with the method described in Steffen Itterheims Book “Learn iPhone and iPad cocos2d Game Development” (using the sudo command in the Terminal) the installation did not work properly and threw some errors. When creating a new project in Xcode, the cocos2D templates just would not show up.

After some googling I found this “unofficial” installer that does the dirty Terminal work for you and that works like a charm.

Thanks Steffen for writing that installer!

How to find an iPhone / iPad’s Document folder in Xcode

Posted: | Author: | Filed under: iOS, Xcode | Tags: , | No Comments »

Sometimes during development when you are writing or reading files from the Documents folder of an iOS Device it is quite useful to have a look at the devices filesystem. Or to the sandboxed Documents Folder of your app to be precise.

Here’s how you do it:

1. Developing on the Simulator

If you are using the iPhone / iPad Simulator for Development, the Documents folder is stored on your Mac’s harddrive:

/Users/user/Library/Application Support/iPhone Simulator/User/Applications/E599AF8C-D765-41A8-B593-A05D242CB701/Documents

You can also find the contents of the app’s “tmp” folder and the app’s preferences in the folder with the long and cryptic name. The only problem is to figure out what cryptic folder belongs to the current version of your app, because Xcode adds a new cryptic folder everytime you build your app in the simulator. So you probably have to find the right folder by looking at the folder’s timestamp.

2. Developing on the Device

Sometimes you have to use a “real” Device for Development. For example if you are using the iTunes File Sharing Feature which does not work on the Simulator. To find the device’s Document Folder for your app, follow this steps:

Xcode 3

  1. Open the Organizer Window in Xcode.
  2. Mark your Device in the left Column.
  3. Find your App in the “Applications” section on the bottom right.
  4. Click on the little triangle left of your App’s name.
  5. Drag the “Application Data” Bundle to your Desktop (or download it by clicking on the black arrow on the right)
  6. Open the downloaded folder (named something like: “com.yourcompany.appname 2011-02-24 10.50.14.277”) to find the Document Folder

Xcode 4

  1. Open the Organizer Window in Xcode.
  2. Mark your Device in the left Column.
  3. Click on “Applications” below your device (you might have to click on your device’s disclosure triangle to see these rows)
  4. On the right side you will see a list of your apps that are installed on this device.
  5. Click on your app’s “Download” Button
  6. Specify a save location and a folder containing your apps document folder will be saved.

Missing Email service in Addthis plugin?

Posted: | Author: | Filed under: Tools | Tags: , | No Comments »

When you use Addthis.com’s share plugin and you are wondering why the email service won’t show up in the share options, here’s what I did wrong:

Apparently the email service needs the “username” parameter to be set. Normally when you generate the addthis code by clicking the button on their site, the username will be a parameter in the URL to the javascript. While I was tempering their code the adjust it to my needs, I somehow lost the username. That made the email service disappear in the addthis layer. As soon as I added the username to the plugin’s setting variable “addthis_config” the email option reappeared.