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.
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:
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:
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.
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).
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?
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.
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.
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:
Open your Font in Fontforge
Goto ‘Element’ -> ‘Font Info’ and change the ‘Family Name’ field
Goto ‘Element’ -> ‘TTF Names’ and change the fields ‘Family’ and ‘Preferred Family’
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.
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.
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:
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
Open the Organizer Window in Xcode.
Mark your Device in the left Column.
Find your App in the “Applications” section on the bottom right.
Click on the little triangle left of your App’s name.
Drag the “Application Data” Bundle to your Desktop (or download it by clicking on the black arrow on the right)
Open the downloaded folder (named something like: “com.yourcompany.appname 2011-02-24 10.50.14.277”) to find the Document Folder
Xcode 4
Open the Organizer Window in Xcode.
Mark your Device in the left Column.
Click on “Applications” below your device (you might have to click on your device’s disclosure triangle to see these rows)
On the right side you will see a list of your apps that are installed on this device.
Click on your app’s “Download” Button
Specify a save location and a folder containing your apps document folder will be saved.
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.