New Icons and Launch Images for iOS7

iOS7 requires new images for the icons and launch image and Xcode now provides a new way of validating that you have all of the required images.

Just to see what Xcode would do, I created a new app from scratch and looked at the images it requires.

Launch Images

I then took a look at what an existing app looks like. The first thing I noticed is that I forgot to include the 100×100 iPad retina image. Then I noticed that the last four launch images are the same as the ones that I already have.

Launch Images

I manually added the Portrait Non-Retina and it automatically found the retina version. Then I added the Landscape Non-Retina and it found the retina. I looked in the .plist for the app and Xcode had added lines for the new files. Since I have over 20 apps I didn’t want to repeat this 20 or more times so I right-clicked on the file, opened the .plist as source, then copied the following lines.


<key>UILaunchImages~ipad</key>
  <array>
    <dict>
      <key>UILaunchImageMinimumOSVersion</key>
      <string>7.0</string>
      <key>UILaunchImageName</key>
      <string>Default-Landscape</string>
      <key>UILaunchImageOrientation</key>
      <string>Landscape</string>
      <key>UILaunchImageSize</key>
      <string>{768, 1024}</string>
    </dict>
    <dict>
      <key>UILaunchImageMinimumOSVersion</key>
      <string>7.0</string>
      <key>UILaunchImageName</key>
      <string>Default-Portrait</string>
      <key>UILaunchImageOrientation</key>
      <string>Portrait</string>
      <key>UILaunchImageSize</key>
      <string>{768, 1024}</string>
    </dict>
  </array>

I pasted these lines into the same place in each of the .plists.

While I was at it, I added a line to my pre-iOS7 images list for the file I forgot to include. That section now looks like this:


  <key>CFBundleIconFiles</key>
  <array>
    <string>Icon.png</string>
    <string>Icon@2x.png</string>
    <string>Icon-72.png</string>
    <string>Icon-72@2x.png</string>
    <string>Icon-Small-50.png</string>
                <string>Icon-Small-50@2x.png</string>
    <string>Icon-Small.png</string>
    <string>Icon-Small@2x.png</string>
  </array>

I then used Xcode to add the new images. (Note: As far as I can tell, you can name them anything you want. I followed a logical extension of the old rules.) I used the same image for Spotlight iPad Retina and iPhone Retina (80×80) so I name it Icon-402x.png.
Xcode added an iPad section to the .plist. The .plist now looks like this:


<key>CFBundleIconFiles</key>
  <array>
    <string>Icon-40</string>
    <string>Icon-iPhone-60</string>
    <string>Icon.png</string>
    <string>Icon@2x.png</string>
    <string>Icon-72.png</string>
    <string>Icon-72@2x.png</string>
    <string>Icon-Small-50.png</string>
    <string>Icon-Small-50@2x.png</string>
    <string>Icon-Small.png</string>
    <string>Icon-Small@2x.png</string>
  </array>
  <key>CFBundleIconFiles~ipad</key>
  <array>
    <string>Icon-40</string>
    <string>Icon-iPad-76</string>
    <string>Icon-iPhone-60</string>
    <string>Icon.png</string>
    <string>Icon@2x.png</string>
    <string>Icon-72.png</string>
    <string>Icon-72@2x.png</string>
    <string>Icon-Small-50.png</string>
    <string>Icon-Small-50@2x.png</string>
    <string>Icon-Small.png</string>
    <string>Icon-Small@2x.png</string>
  </array>

Xcode has a new folder type for Asset Catalogs. I did not convert my icons to asset catalogs, but it looks like a good way to manage assets.

Developing Apps for iOS

Recently several high-profile developers and teams shared their list of tools that helped them make apps for iPhone and iPad. I’m not as experienced with app development as they are but I though it might be useful for some new developers to see what I use to make my apps.

Obviously I use Xcode extensively for writing and compiling code. In a previous article I discussed how I turned on most of the compiler options so that my code is more robust. I’m still not fluent in ‘find and replace’ operations and Xcode crashes on me when I try to duplicate files, so I use BBEdit a lot for tweaking the code. I’ll take existing .m and .h, dup them in the finder and then use BBEdit to make global changes so that the new method name is changed everywhere in the file. I also use BBEdit to edit the .sql files that contain my data. Which brings me to the next most important program I use.

Most of the apps that I wrote are based on existing CDs or web pages. We used Filemaker Pro when we made the wordlists for the original CDs but we’ve switched to a web-based editing format instead. We have a bunch of PHP scripts that edit data in MySQL databases. It allows distributed editing of the content and we have a script that takes the data from MySQL and writes it out to an Xcode readable .sql file. We use a Firefox plug-in, SQLite Manager to verify the SQLite files that our scripts produce and occasionally we edit them as well.

Our graphic designer likes Flash so we use an older version to make the icons and graphics in the game. All of the photos were originally edited in Photoshop and we use it occasionally if we need to adjust the photos so they look better on devices. Because we have hundreds or thousands of images in our apps, we turned off automatic compression in the compiler and use ImageOptim to reduce the file size of the images and graphics. It makes a significant difference in the app size as I discussed in this article. I use Acorn to do quick edits to icons and to make placeholders. I had the free version but upgraded when they had a sale. I don’t do much in the way of photo editing, but if I did I’d use Graphic Converter. It has tons of filters and features for massaging photos and is only $40.

We do a lot of moving files back and forth from the server to the desktop and use Cyberduck for SFTP transfer. We used to have our own server but now we use a VPS hosted at Linode and are very happy with it—not to mention the fact that it costs $25/month (including backups) rather than $200.

We have a bunch of bash scripts for renaming sound files and Flash file exports and use Renamer 4 to rename files.

Since almost all of our apps rely extensively on sounds, we spent a lot of time in SoundStudio recording, cutting, and cleaning up the sounds. Audacity has matured enough that we use it on machines that we don’t have a SoundStudio license for or when we hire extra people to do massive amounts of sound cutting. We use a simple bash script to convert the files from .aiff to .m4a format.

From time to time we need to use formatted HTML in our apps. For example, we might want to highlight the target word in a sentence. We’ll export the sentences from the database and use Bean to color the target word red. Then export the text to HTML, clean up in BBEdit, and import to MySQL.

The import, export, and editing of the database is done with PHPMyAdmin and occasionally command line imports.

Unlike other teams, we don’t really need much communication. The little communication we do is by email and occasional in-person meetings.

I keep track of what needs to be done in a simple list in Notes.

That’s about it. I just bought a Mac Mini for around $1,000 since my Laptop won’t run Mountain Lion. Our total investment in software is $99 per year for the Xcode developer license and $25/month for the server. I’ve been using BBEdit forever so I don’t know how much I’ve paid for it, but a new copy is $49. You can get a free copy of TextWrangler from them that does most of what BBEdit does. Most of the rest of the programs that we use are either fee or cheap. We’ve donated a couple hundred dollars to Cyberduck and Audacity since they are so incredibly useful. We have old versions of Photoshop and Flash but if you were starting from scratch there are lots of replacements that are inexpensive. Acorn and Pixelmator work just as well as Photoshop for most or our graphics. If you are on a budget, you can easily get started on app development for less that $1,000. But even if you have money to burn, you don’t need to spend more than $2,000 to get all the tools you need.

Finding substrings in iOS

It one point I experimented with using titles on my answer buttons to keep track of which answer was selected. I switched to tags since they are integers and they are easier to use in this particular implementation. In any case, I though it interesting to show how to get a substring from a string. My titles are of the form, ‘Answer1’, ‘Answer2’, … ‘Answer16′. I really only need the last one or two digits. I pass an NSString into the delegate method from a button press.


- (void)checkBoxTapped:(UIButton *)buttonPressed {
    [[self delegate] quizAnswered:buttonPressed.currentTitle];
}

Then I grab either the last digit or the last two digits from the string.


NSString *answer = [selectedAnswer substringWithRange:NSMakeRange(6, 1)]; // wrongAnswer - wA
if (selectedAnswer.length == 8) wA = [selectedAnswer substringWithRange:NSMakeRange(6, 2)];

I was doing a string comparison to decide which question was answered,


if ([answer isEqualToString:@"1"] || 
    [answer isEqualToString:@"2"] || 
    [answer isEqualToString:@"3"] || 
    [answer isEqualToString:@"4"] ) {
    // do something
}

What I should have done is convert the string to an int and then do a simple comparison.


NSInteger answerAsInt = [answer intValue];
if ([answerAsInt < 5 ) {
    // do something
}

Null objects and NSArrays


- (void)displayWithParentView:(UIView *)parentView
                    withItems:(NSArray *)items
                 withOldItems:(NSArray *)oldItems  {
    
    NSString *pictR1C1Name = items[0];
    NSString *pictR1C2Name = items[1];
    NSString *pictR2C1Name = items[2];
    NSString *pictR2C2Name = items[3];
    
    UIButton *oldR1C1Button = (oldItems[0]  == (id)[NSNull null]) ? nil : oldItems[0];
    UIButton *oldR1C2Button = (oldItems[1]  == (id)[NSNull null]) ? nil : oldItems[1];
    UIButton *oldR2C1Button = (oldItems[2]  == (id)[NSNull null]) ? nil : oldItems[2];
    UIButton *oldR2C2Button = (oldItems[3]  == (id)[NSNull null]) ? nil : oldItems[3];

This is a snippet of the code I use to put pictures on the screen. The old pictures slide off the screen and the new ones slide on. When the screen is first initialized the oldItems array has not yet been initialized. So it is null. I can’t put a null object into a button though, so I test to see if there is an null object in the array and then set the button to nil. Otherwise, I set the button to the button that has been passed in from the array.

Likewise, I can’t put null objects into an array—recall that the way to define an array is


NSArray *newArray = [NSArray arrayWithObjects:object1, object2, nil];

The first nil object terminates the array. So to add nil objects to the array you need to first convert the nil to an object.

So you basically do the reverse of the code above to convert nil to an null object.


object1 = (object1  == nil) ? [NSNull null] : object1;
NSArray *newArray = [NSArray arrayWithObjects:object1, object2, nil];

ImageOptim

in a previous post I discussed using ImageOptim to reduce file sizes for websites. I also tried it on some apps. Our apps use lots of images and sounds so they are quite large. The table shows the reduction in size when I used ImageOptim and turned off PNG compression in Xcode. You need to turn off PNG compression because Apple uses their own compression method that is supposed to optimize display time but has a side effect of making file sizes larger. I don’t see any difference in display time, so I’ve opted for smaller file sizes.

 
Title
Original Size (MB) With ImageOptim % Reduction
Show Me…CNS  9.104  7.739 15%
Minimal Pairs 16.723 15.090 10%
Show Me… 38.205 29.682 22%