Upgrading to Xcode 4.3

February 18th, 2012 5 comments

Xcode 4.3 was released on February 16th. It is now truly a Mac App Store application.

With Xcode 4.2, you downloaded an “Install Xcode” application from the Mac App Store, which in turn “installed” Xcode in the usual location, “/Developer”, which is a folder named “Developer” at the root of your hard drive.

Furthermore, if you wanted Xcode to automatically update (from the Mac App Store), you had to keep the “Install Xcode” application (1.8 GB) in your Applications folder, as that was what the the Mac App Store actually updated; you then had to run “Install Xcode” manually to update.

This has changed for the better.

Xcode.app now installs directly in the Applications folder. In fact, it will helpfully propose to move the older, obsolete installation to the Trash for you:

Xcode move to Trash

Xcode is also smaller, since a lot of (probably) lesser-used software has moved to optional downloads. Peter Hosey has a comprehensive list.

In my case, I had one more thing to do: install the command-line tools. They can be found in Xcode > Preferences > Downloads > Components. To get them working properly, here is what I had to do:

  1. sudo xcode-select -switch /Applications/Xcode.app
    This updates the command-line Xcode tools to point to the new location, and is only important if you are migrating from 4.2. A new install should work fine.
  2. Install autoconf. Some of my projects (and many unix-based ones) use autoconf to generate ‘configure’ files, and this tool is missing from the new install. It was present in earlier installs, so I have filed a radar.
    In the meantime, I was able to download the latest version (2.84 at the time of this writing) and install it with the usual ./configure; make; sudo make install dance
  3. Update any scripts that have a hard-coded ‘/Developer’ path.
    Since everything is in the ‘/Applications/Xcode.app’ bundle, the new path is ‘/Applications/Xcode.app/Contents/Developer’. If you don’t want to hard-code it (for instance, if you use Xcode 4.3 but your colleagues are still on Xcode 4.2), you can use the output of xcode-select --print-path to find the path to ‘Developer’ on any system. This works in Xcode 3 as well.

Xcode 4.3 requires MacOSX Lion 10.7.3.

Categories: iOS, MacOSX, Xcode Tags:

Xcode 4.2 and older iOS devices

December 18th, 2011 3 comments

If you want to build software using the new default templates on Xcode 4.2, you have some work to do for older devices (anything that can’t run iOS 5).

For some unknown reason, the variable $(ARCHS_STANDARD_32_BIT), which used to expand to armv6 armv7 now expands only to armv7.

Furthermore, there is a new entry in the default Info.plist which will prevent Xcode from even uploading the binary to your device.

Finally, there are issues with the compiler’s ‘thumbnail generation’ code ‘Thumb code’ generation in Xcode 4.2. You can disable that compiler option for armv6 builds in Xcode.


I have a 2nd generation iPod Touch that I use daily. It runs iOS 4.2.1, the latest it will ever run. This is essentially the same hardware as an iPhone 3G in terms of capabilities.

I also have a 1st gen Touch, but it’s getting used less and less as I target iOS 4 as the earliest capable version. I’m not going to iOS 5 yet because my main device is still iOS 4.

When I create a new project, I use iOS 5 as the SDK and iOS 4.2 as the deployment target. In theory, this allows me to target all devices that can run iOS 4, which includes my beloved Touch.

To make this work properly, you will want to do three things:

  1. In your Project’s Build Settings, locate the “Architectures” line. It should say $(ARCHS_STANDARD_32_BIT). Edit it to contain two entries: armv6 and armv7.
  2. In your Project’s Info.plist, locate the entry for “Required device capabilities” and delete it.
    If you expand it, you will see that it contains only armv7.
  3. Bonus! Thanks to @jamesthomson, there are issues with clang-llvm 3.0 on armv6 devices.
    In your Project’s Build Settings, locate “Other C flags” and add “-mno-thumb” to the armv6 architecture.

When radar comes back online, I’ll file the bug (which will undoubtedly be marked “Duplicate”)

Categories: Development, iOS, Xcode Tags:

iPad or Netbook?

September 6th, 2010 4 comments

[This is not as developer-oriented as my other posts, but many people asked me to share this story so here goes... —Philippe]

The Setup

We have three children in the house: twin teens and one pre-teen. We also have three usable (read: Intel-based) computers. I have an original MacBook Pro, my wife has a Mini and the kids share another (recent) Mac Mini.

Three kids on a computer was becoming a constant source of tension among them, which I wanted to alleviate. Their Mini is the most powerful of all our machines with a fairly decent video card, a large display and a Wacom Intuos 3 they use all the time in Painter and Acorn.

The Problem

The twins want their own “computer”. They want to be able to surf the web, type reports for class, chat with their friends and watch videos. And go on Facebook.

If money was no object, I would buy them each a MacBook. They know how to use it, won’t get viruses, won’t always come to me for questions, and all our current apps (Pages, iTunes, Firefox, Adium) will work just fine. Plus they would be able to sync their iPods before going to school without it being a dramatic production 5 minutes before they leave, because they must have the latest video on there for the bus ride.

But of course, money is an issue. Plus, at this rate, they won’t make it through University with the same MacBook because by that time, the MacBook will be 7 years old. So I was looking at buying 4 MacBooks over the next 3-4 years, which is less than ideal.

Enter the iPad

Looking at their usage patterns, I figured that an iPad for each teen would cover 70-80% of their computing needs (maybe with a stand and an external keyboard, too). It seemed like an ideal solution.

Buy each teen an iPad and they can:

  • Surf the web, chat, write papers, watch (some) videos
  • Have a small, long-lasting-battery device they can take anywhere
  • Sync occasionally to the main computer, as needed

In return I get:

  • to buy two iPads for the price of one MacBook (a 50% saving!)
  • a lot less nagging until College
  • almost no maintenance
  • hopefully a lot less conflicts around the family computer
  • peace of mind (no webcam is a plus!)

So I bought one iPad and lent it to each child for her exclusive use, for a week. They would tell me if my assumptions were correct.

iPad Results

Being the new toy, the iPad got quite a bit of play at our house. Since it is small and portable, it can be used anywhere. I like it for books and rss feeds, my wife watches CrunchyRoll, YouTube and Facebook are perennial hits.

I also took the iPad for a week at WWDC as my note-taking, twittering machine and that was a smash hit, thanks to SimpleNote and Notational Velocity.

Overall, we all like the iPad. We really wished it had separate user accounts, or at least a “guest” mode so the one person who’s responsible for it doesn’t have to expose his or her mail, Twitter, Safari bookmarks, contacts, etc… to everyone else who wants to use the one iPad.

No Flash

The biggest problem with the iPad was the lack of Flash. I personally don’t care for Flash and its battery-sucking, lap-melting performance, but my daughters watch a lot of Japanese cartoons and play Flash games on Facebook, and those will take some time to transfer to the new world of iOS apps, HTML5 and H264.

A secondary concern was the iPad’s unitasking. I view it as a feature but they like to have on their screen an IM client, a YouTube video and some web browser / text editor / paint program. You can’t easily do that simultaneously on the iPad

Netbooks to the rescue!

I have an original OLPC and when I (quickly) got bored with it, my plan was to recycle it to my children as a small laptop. That experiment is mostly a failure du to the laptop’s anemic performance and inability to hold a decent charge. Seriously, its browser is slower than the Wii and forget about Flash!. However, it has been a good way to teach Python to my youngest daughter, and the laptop’s whimsical, kid friendly design is a hit wherever she takes it.

So you can understand my reluctance about netbooks. It was out of the question that I would buy my daughters a 600$ laptop: those are heavy, ugly monstrosities; try to get anything decent and you soon get within striking distance of a MacBook so why not get a MacBook?

We started talking about netbooks. My kids understood they were slower than the Mac Mini, and had a small screen and keyboard but those were not deal-breakers by any means. In fact, they prefer the small form factor because (duh!) it takes less space and is more “personal”, a feature they really appreciated in the iPad. The intimacy of this device is a feature all by itself.

Just as for the iPad, I decided to buy a small netbook as an experiment. My conditions were simple:

  • it cannot cost more than 400$
  • colors don’t matter. You’ll get to put stickers on it if we keep it (because in three years, when it’s really time for a MacBook, that thing will be old and no one will care about it)
  • it cannot run Windows. I do not want that administration task.

I found an HP Mini 110, which had the additional advantage of being a good candidate for a hackintosh, should I end up with this system. And the price was right at 280$.

Hardware-wise, the bilingual keyboard is surprisingly good. The trackpad is a little too sensitive and its buttons a bit mushy. I will probably buy an external, corded mouse in the next few days.

There are three USB ports, one SD card slot (perfect for their digital cameras) and one VGA-out port.

It comes with Windows 7 Starter, which is an restricted version of Windows 7. When I told my daughter that she could not even change the desktop wallpaper, she was appalled and took it as the best reason not to run Windows on this system…

As I was downloading Ubuntu Netbook (see below), she took the time to go through the first-run experience of Windows 7 because she knew it did not matter, we were going to erase it anyways. As a typical user, she was almost forced to install a ton of crapware programs and trial editions (Norton Antivirus? Really?). There was even a HP-branded user interface that installed itself in the bootloader! I kid you not! Getting rid of this abomination to be able to access the BIOS and boot from a USB key was not trivial.

Enter Ubuntu

Ubuntu Linux is the version I use at work. They have a netbook edition which is optimized for small screens and slower processors, so that is what I downloaded.

There’s even a manga comic, so that’s a big hit in this house!

You install the .iso on a USB stick (which is easiest to do under Windows than Mac, mind you) and from there, select the USB stick in your boot menu. I had to press Esc and then F9 on my HP Mini to get the menu, instructions which were on the computer’s screen. From there, follow the prompts and either run from the USB stick or install to the hard drive.

Ubuntu is available in many languages (from the same .iso), we chose to install French. It even recognized the French keyboard on the netbook, which was a concern of mine.

The overall look of Ubuntu is very good. Easily-readable text, good French translations and some obvious attention to details like rounded corners and fade-in, fade-out animations à la Growl.

Though it did download and install updates for over an hour, once we installed the Flash Player plugin all the sites that were previously inaccessible on the iPad became usable.

I was expecting everything to work, and everything did: the keyboard, trackpad, battery indicator, volume control, backlight control. It even goes to sleep when you close the lid!

I have not gotten the built-in speakers to work, but earphones work fine.

I only had one scare. My initial install failed to set up the wireless card. We knew it worked because Windows had detected it when we first booted, and I spent a few hours googling a solution and getting n00b-level advice on IRC.

The solution was simple: when installing, plug an ethernet cable into the netbook. As part of the install process, Ubuntu downloads additional files as needed. With this simple action, everything worked great.

Performance is very good. It appears subjectively faster than Windows 7 Starter on the same machine. I was worried about Flash performance but it is acceptable, definitely working for 360-480p video (the screen is 1024 x 600). Facebook games are fine.

Applications

We’re still evaluating this, but even though the big application is Firefox, we have found suitable replacements for Mail, IM and even homework. There are apps to manage your iPod which work fine with their Nanos.

They miss the “big” apps like Painter and Acorn (and to a lesser degree, Pages and iMovie) but that’s what the main family computer is for.

I have not worked out a backup strategy yet. I have a Time Capsule for the Macs in the house, which works with Time Machine. For their netbooks, I think a simple, cron-based hourly rsync of their home folder to a folder on on the family computer could do the trick.

Conclusions

They say that Linux is free only if your time is worth nothing, and that has some merit. But once it is running, it is very easy to use.

Ubuntu in particular is very discoverable. The netbook-specific version shows an attention to details like the small screen and the important applications, and that made all the difference. Even the application installer is easy to use. And it’s all free! Which amazes my daughters because I make my living writing software for money.

The Ubuntu Software Center in particular makes it trivial to discover, install and uninstall software. When she was not totally happy with the built-in Empathy‘s support for MSN Chat, my daughter found and installed amsn by herself. That is ease of use!

Aside from my one scare with the wireless card not working, the experience was very positive. In fact, I just bought a second, identical netbook (10$ less this time) and the install was seamless. We did not even boot into Windows.

The best part is I bought two netbooks for the price of one iPad. Another 50% savings! Even more if you account for the inevitable iPad apps like Pages and Keynote, and the external keyboard and dock. All of these easily add 100$ to the price of any iPad.

I always hope that my daughters will become proficient with computers, not because they know to “click there” to go to the Internet but because they have a higher-level understanding of how Operating Systems operate, regardless of MacOSX, Windows, Linux or more.

Because we have no idea what the computers from the future look like. And I want them to be ready.

Categories: MacOSX Tags:

Introducing PhFacebook, a Cocoa framework to Facebook’s API

August 29th, 2010 12 comments

For the upcoming version of iChibi, I needed a MacOSX interface to Facebook’s API.

There are several iOS libraries (FB Connect, ShareKit…) but I found only one that was MacOSX-specific: MBAbeFook, which implements the (deprecated) Facebook REST API.

This was a problem because:

  • I need extended permissions, and it’s a song-and-dance to get those using the REST API
  • The authentication UI from REST may present checkboxes to the user for extended permissions.
    Users don’t check boxes. They click “I agree”…
  • The REST API is deprecated.

So I wrote my own. PhFacebook is an embeddable MacOSX framework to easily access Facebook’s API.

  • Uses Facebook’s new ‘graph’ API internally, handles OAuth in a WebView for you and returns JSON strings.
  • Comes with a sample application to show you how to use it.
  • Supports extended permissions.
  • Localized in English and French.

Find it on github. MIT-licensed.

Categories: Development, MacOSX Tags:

Eight guys, four weeks, one dream

February 16th, 2010 2 comments

A software coop

At our local Cocoaheads chapter, we started dreaming in December… What if we pooled our resources and multiple talents to create a software “co-op”? Shared resources, low buy-in, extra exposure and marketing…

Over the holidays, Cocoaminded was born. We have a domain, so we must exist, right?

Early January, Mark had an idea. What if we all worked together on a small iPhone app to promote our other apps, and learn something in the process?

Introducing Tweety10

Mark’s idea was to expand on his HockeyTweet to create an Olympic-themed Twitter client. It would have a live newsfeed (from Twitter, of course!), medal count and schedule. It would use web services to serve the data

And just like that, we decided to start what became Tweety10.

The first 80%

We all got together on Sunday, January 10th at The Code Factory and brought our laptops. Mark even brought his 24″ display. At 9:30, we had a kickoff meeting where we decided that at 5:00, no matter what, we would all go home. And we would decide if the app was in a good enough shape to continue working on it, with the goal of submitting within two weeks to the App Store.

I was nominated as Project Manager, which means that I was responsible for the big picture, so to speak. Given my past experience, here is what I had planned:

  • Each feature of the application, for example the News view, the Medals view, etc… was written on a 3×5 index card. Features would be then assigned, and divided into subfeatures as necessary. For the News view, you had the actual view, the Controller (UITableViewController, in this case) and the model, along with the web service. We wrote those subfeatures on cards
    The idea was, whatever was on a card should represent about an hour’s worth of work. If it took more than an hour, you made a new card. When you were done, you asked for a new card.
  • Version control with Mercurial.
    I suggested Mercurial (hg) early on because it is fast, simple and distributed. It also has a fairly quick learning curve, meaning I would not have to spend a lot of time explaining it to everyone.
    Mercurial had a couple of small glitches that were due to my unpreparedness, but overall it was very satisfactory.
  • We would use BitBucket.org to store our common code repository.
    BitBucket has a free, private repository (and unlimited public repositories). It was extremely simple to create the private project and add the other seven developers as writers to the project. You can also assign read-only access if you want: it is simple and quick, much like Mercurial itself.
  • Starting from the skeleton application (a variant of the Tab Bar Application Xcode template), we would add source code and resources as needed, and push to the common repository as often as possible. Continuous integration was the word.

I spent my day making cards, troubleshooting issues, helping out with code problems and generally having a blast integrating all of the code into a build system on my own computer. It was exhilarating to keep feeding six smart people with enough information to keep them busy, while at the same time making sure that they are not stuck on a problem or bored and going off-spec. The index cards were a hit, and BitBucket performed admirably.

At the end of the day, we decided we had an app, and it was worth continuing towards our goal of putting an app in the App Store.

The other 80%

Since we would not work in the same area anymore, I immediately transcribed all the cards on a Wiki page in BitBucket. This allowed us to put our name next to a virtual card and claim it. We could add cards, and mark them as complete when the work was done.

We started using Skype’s Chat feature to create a private chat amongst all of us. The great thing was, you did not have to stay logged-in like you would for IRC. If you disconnected from the chat, as soon as you re-connected Skype updated your chat window and you could see all of the conversation that you had missed. This is a great feature.

Although it was not formal, it was very helpful to meet two to three hours every week for NSCoder Nights. It was a great way to gauge progress and help each other out with all the little things that stop us from time to time.

We finalized our artwork and installed localizations, keeping abreast of changes in localizable files as much as possible (this late, the changes were far between).

Real artists ship… then get rejected

We submitted to the app store a week before the Olympics were due to start, and after three days got rejected because we used the word “Olympics” in our keywords. Oops! I wonder how people who live on the Olympic peninsula feel… We removed the keyword, re-submitted and after another four days of waiting…

Tweety10 is available on the App Store. It’s free, give it a try!

Post-mortem

Having a real, in-person kick-off day for the project helped tremendously. This would not have happened otherwise. Most of our subsequent interactions were online via email, Skype or BitBucket and if we had not smoothed out the communication channels beforehand, the friction would have been too great.

Mercurial is a great version-control system. Once we got past the initial hurdles of merging (hg does not come with a built-in merge tool, you have to set it up) and pushing (Mercurial Keyring Extension is a must).

BitBucket, with its one free private project, was an awesome instrument in communication via code and issues. You get an email when an issue is created or updated, and you can resolve issues by pushing a change containing text like “Fixes #23″.

Finally, I was delighted to see that as a group, we worked really well together. I hope we all gained some valuable knowledge and experience with this project; I certainly did.

This was really a case of the whole being larger than the sum of its parts! I hope you will enjoy the app and the 2010 Winter Olympics in Vancouver, Canada.

Categories: Development Tags:

Multiple developers, one iPhone app

February 10th, 2010 2 comments

I am working on an iPhone project with seven other iPhone developers, and we all have individual development certficates (the project did not require a group certificate, and we all had ours already).

Since one has to sign code to run outside the simulator, we all edited the Info.plist’s Bundle Identifier to match our certificates (mine was com.casgrain, as you can guess).

This leads to a permanently-modified file in your local copy of the source repository, one that you have to ensure you do not commit. It’s not very neat, and it is error-prone. And if you want to genuinely modifiy the plist, you must discard your changes, do the modification, commit and re-do your changes. Not pleasant.

I wanted to use plist pre-processing to solve this issue, since it will replace environemnt variables in the plist before using it, for instance to sign code.

The goal is to replace this:

	CFBundleIdentifier
	com.myCompany.${PRODUCT_NAME:rfc1034identifier}

with this:

	CFBundleIdentifier
	${DEVELOPER_DOMAIN}.${PRODUCT_NAME:rfc1034identifier}

Pre-processing supports environment variables, but not any environment variable. If you define a variable in ~/.profile (if you use bash or a bash-compatible shell), this does not work.
You have to define the variable in ~/.MacOSX/environment.plist, a special plist that is read at login time.

To define this variable, follow these three simple tasks in Terminal. You only need to do them once.

  1. Create the `/MacOSX folder if it does not exist. If it is already present, this is harmless
    	mkdir ~/.MacOSX
    
  2. Add the environment variable
    	defaults write ~/.MacOSX/environment DEVELOPER_DOMAIN -string "com.yourdomain"
    
  3. Ensure that the plist is human-readable and not compressed XML, in case you want to edit it later with a text editor
    	plutil -convert xml1 ~/.MacOSX/environment.plist
    

You will need to log out and back in for those changes to take effect.

Now, do the repkacement above in your Info.plist, substituting “${DEVELOPER_DOMAIN}” for “com.myCompany” or whatever the reverse-domain was for your project.

With this modification, you should now be able to build for the device without changing the plist every time.

Categories: Development Tags:

Tap-enabled UITableView section headers (and footers)

January 31st, 2010 Comments off

Displaying ads

For a project I’m working on, I had the need to display inline ads within a UITableView of news.

My initial thought was simply to create a different kind of cell every 10 cells, and that cell knows how to display itself:

- (UITableViewCell*) tableView: (UITableView*) atableView 
  cellForRowAtIndexPath: (NSIndexPath*) indexPath 
{
  static NSString *NewsCellIdentifier = @"NewsCell";
  static NSString *AdCellIdentifier = @"AdCell";
  
  UITableViewCell *cell = nil;
    
  // Set up the cell...
  if (0 == indexPath.row % 10)
  {
    CMAdImageTableViewCell *adCell = 
      (CMAdImageTableViewCell*)[tableView dequeueReusableCellWithIdentifier: AdCellIdentifier];
    if (adCell == nil) 
    {
      adCell = [[[CMAdImageTableViewCell alloc] 
        initWithStyle: UITableViewCellStyleSubtitle 
        reuseIdentifier:AdCellIdentifier] autorelease];
    }
    /* more cell customization... */
    cell = adCell;
  }
  else
  {
    CMNewsTableViewCell *newsCell = 
      (CMNewsTableViewCell*)[tableView dequeueReusableCellWithIdentifier: NewsCellIdentifier];
    if (newsCell == nil) 
    {
      newsCell = [[[CMNewsTableViewCell alloc] 
        initWithStyle: UITableViewCellStyleSubtitle 
        reuseIdentifier: NewsCellIdentifier] autorelease];
    }
    /* more cell customization... */
    cell = newsCell;
  }
  
  [cell setNeedsDisplay];
  
  return cell;
}

This works. There is a CMAdImageTableViewCell created every 10 cells. And since the UITableView delegate can get the -(void) tableView: didDeselectRowAtIndexPath: message, you have a chance to intercept a tap on the ad cell and send the user to the ad’s website.

However, you have to do some bookkeeping. For instance, the total number of cells will be the sum of all the news cells and your ad cells, or [news count] + [news count] % 10. You also have to find the proper offset in your model when you get an indexPath, etc. Not difficult, but annoying.

Another issue is that TableView cells all look and behave the same. An Ad cell doesn’t say “I’m an ad”, it just says “I’m another cell”, by the way it scrolls. Your ad design will probably be different than your news design to tell them apart, but it would be nice to have another, subtle way to differentiate the ads.

Section Headers

UITableViews can be separated in sections, with an optional header and footer. These sections stay on screen, at the top and/or bottom, and are overlaid on top of the UITableView’s actual data. They can be semi-transparent, allowing to to see the table’s data underneath. You can see sections in action in many apps, including the Contacts application on your iPhone: notice the section headers “A”, “B”, “C”.. as you scroll down?

To create sections, just return the number of sections in your delegate’s -(NSInteger) tableView: numberOfRowsInSection:. Once you specify more than one section, you can set a section header’s appearance by responding with a UIView to -(UIView*) tableView: viewForHeaderInSection: in your UITableView’s delegate.

This is a full-fledged UIView, so you can do things like drawing with Core Graphics or adding a complete view hierarchy. For the simple case of an ad, if you already have a PNG with the ad to display, you can simply do:

- (UIView*) tableView: (UITableView*) tableView 
  viewForHeaderInSection: (NSInteger) section 
{
  /* assumes your tableview is 320 wide, makes a section header 80 pixels high */
  customView = [[[UIView alloc] initWithFrame: CGRectMake(0.0, 0.0, 320.0, 81.0)] autorelease];
 
  UIImageView *imgView = [[[UIImageView alloc] initWithImage: myPNGImage] autorelease];
  /* makes the views slightly transparent so you can see the cells behind them as you scroll */
  imgView.alpha = 0.7;
  customView.backgroundColor = [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 0.7];
  
  [customView addSubview: imgView];
  
  return customView;
}

I made the header with a semi-transparent white background so you can see a little bit of the underlying news as you scroll by, giving the overlay a nicer appearance. You can adjust it to suit your needs.

This is great. The ads stay on-screen, on top of the content, and they don’t interfere with it.

There’s only one problem…
You can’t tap on section headers. There is no delegate method to tell you what section header was tapped.

UIButton to the rescue

What if, instead of embedding a UIImageView, you embedded a UIButton in your customView? UIButton is a subclass of UIView, but it handles events and can dispatch on target-action. Plus, you can add an image to a button! Let’s try this:

- (void) headerTapped: (UIButton*) sender
{
  /* do what you want in response to section header tap */
}
  
- (UIView*) tableView: (UITableView*) tableView 
  viewForHeaderInSection: (NSInteger) section 
{
  customView = [[[UIView alloc] initWithFrame: CGRectMake(0.0, 0.0, 320.0, 81.0)] autorelease];
  customView.backgroundColor = [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 0.7];
 
  /* make button one pixel less high than customView above, to account for separator line */
  UIButton *button = [[[UIButton alloc] initWithFrame: CGRectMake(0.0, 0.0, 320.0, 80.0)] autorelease];
  button.alpha = 0.7;
  [button setImage: myPNGImage forState: UIControlStateNormal];
  
  /* Prepare target-action */
  [button addTarget: self action: @selector(headerTapped:) 
    forControlEvents: UIControlEventTouchUpInside];
  
  [customView addSubview: button];
  
  return customView;
}

The difference with UIImageView is the target-action method. We added a new target (self), with the method headerTapped: (defined above) for the event UIControlEventTouchUpInside. You can view all events handled by UIButton, but I recommend TouchUpInside because it is sent when the user lifts her finger while inside your button. If she slides out of the button the action is not sent and she can effectively “cancel” the button’s activation.

Voi|à! You now have a section header that responds to taps.

Notes

This code uses hard-coded numbers for example purposes. Use macros or consts in your own code, not magic numbers!

Also, creating custom UIViews is expensive. You don’t want to do it every time viewForHeaderInSection: is called as this will impact performance. Once you create a UIView, save it in a mutable array or dictionary and cache it for the next time you are called.

Categories: Development, MacOSX Tags:

Automatically localize your nibs when building

December 22nd, 2009 21 comments

This post applies to all Cocoa apps, whether on the desktop or on the iPhone.

When you want to localize your application, you can take several routes.

No nibs, only .strings files

The first one is to not use nibs (or xibs, in the new parlance). If you build everything programmatically, +alloc and -init-ing your controls and your views, you can store all the strings in .strings files. These files are simple key-value pairs of Unicode-encoded strings. Call the files “Localizable.strings”, drop them in the appropriate language folders (English.lproj, French.lproj, etc…).

	English.lproj/
		Localizable.strings
			[file contents]
			"Dawn" = "Dawn";
			"Sunrise" = "Sunrise";
			"Sunset" = "Sunset";
			"Dusk" = "Dusk";
	French.lproj/
		Localizable.strings
			[file contents]
			"Dawn" = "Aube";
			"Sunrise" = "Lever";
			"Sunset" = "Coucher";
			"Dusk" = "Crépuscule";

To use, simply call call:

	NSString *str = NSLocalizedString(@"Dawn", nil);

This technique is important even if you have nib files, because most of your strings are probably in .strings files already. Don’t use hard-coded strings for anything that is user-visible. Only use hard-coded keys.

Use nibs

This looks easy: duplicate your English nib, move it to the appropriate folder, open it in Interface Builder and translate all the strings directly in IB.

This is very bad. Don’t do it.

  • It’s unmaintainable: as soon as you change one thing in the original nib, you have to do it in one or more other nibs.
  • It’s error-prone: you can easily disconnect a binding without realizing it, and Undo support in IB is spotty at best (I don’t rely on it). By the time you realize your mistake, it may be too late and you have to revert everything.
  • It’s not versionable: although xib files are XML files, they are not meant to be user-editable. Think of them as binary files. You wouldn’t merge binary files now, would you?
  • It’s hard to do: there are many nooks and crannies where localizable strings are found in IB (tooltips?), you’re bound to forget some of them in some language.
  • It needs a developer: you would not hand off a nib file to a translator and expect him to know all of the above: there is some training involved. And even if you have the Fear of God when editing nib files (because you’ve been burnt before by a disconnected IBOutlet), chances are your translator has no such qualms.

Translators want strings files, not nib files

You could use Wil Shipley’s approach of translating everything at run-time. That approach has one great advantage: everything is driven by strings files, which only contain strings (duh!). Your translator(s) will do a great job with them, and you can easily diff the results in your own version control system when the translations come back.

There are, however, drawbacks to this approach. Since everything happens at run-time:

  • You have to ship and execute more code than necessary (this is a minor point, but still valid for the iPhone since it is very resource-limited).
  • You can only see the results by launching your app in the appropriate language, switching using the International Settings panel, which is tedious.

A compile-time approach

My approach expands on Brian Dunagan’s use of ibtools and genstrings.

Xcode has excellent build scriptability due to Run Script build phases. In this example, we will use a script to generate a localized French xib from an English xib, using a strings file as a template for translation.

First, create a French version of your xib file by adding a French localization to your English xib file.
Assuming it is called “MainWindow.xib”, select the xib file, choose File > Get Info and in the “General” pane click “Add Localization”. Type “French”.

This will create the “French.lproj” folder, which will contain a copy of the English MainWindow.xib.

Next, add a Run Script phase to your application target:

Run Script build phase in Xcode

Finally, enter this as your script:

# Extract English strings (use this to check if you added new strings to your nibs)
ibtool --generate-strings-file Resources/English.lproj/MainWindow.strings Resources/English.lproj/MainWindow.xib
# Generate French interface
ibtool --strings-file Resources/French.lproj/MainWindow.strings --write Resources/French.lproj/MainWindow.xib Resources/English.lproj/MainWindow.xib

Repeat each pair of lines for each xib you need to localize, and adjust the names accordingly.

The first command extracts all the localizable strings from your English xib, and stores them in English.lproj/MainWindow.strings. This is your reference file: add it to version control, but you do not need to add it to your application. You can add it to your project, but make sure it is not included in your app bundle (it is useless at runtime).

The second command takes a French-localized version of the same strings file (French.lproj/MainWindow.strings) and, using the English xib as a template, generates the French xib.

Wait a moment…

If you followed so far, build your app. The script should fail, because French.lproj/MainWindow.strings does not exist yet. Just make a copy of English.lproj/MainWindow.strings and put it in the French folder. Just like the English MainWindow.strings, you want to add this file to version control and your project, but not to your app’s resources.

If you build again, everything should go fine and your French MainWindow.xib should be created… in English.

Translation

Of course, you have to translate the French MainWindow.strings. Mine looks a bit like this:

/* Class = "IBUIBarButtonItem"; title = "Done"; ObjectID = "138"; */
"138.title" = "Terminé";
/* Class = "IBUIBarButtonItem"; title = "Today"; ObjectID = "140"; */
"140.title" = "Aujourd'hui";
/* etc... */

You can send this file to your translator, and instruct her to only translate the words in quotes on the right-side of the equal (“=”) sign. Don’t touch anything else.

But… the Fear of God?

Everything else in this file is necessary for ibtool to do its job properly, and should not be touched. There are two safeguards against you (or your translator) accidentally touching this information:

  1. You have the original English file. When the file comes back from your translator, you can diff it against the original (which is in English, remember?) and see that she has followed your instructions (or not). It should be pretty easy to spot the differences with FileMerge.
  2. Every build, the script re-creates the English MainWindow.strings file. Your version control system should flag any differences immediately. For instance, if you added a label, you would see it in your new English file and you could apply the exact same change to your French file, and make a note to send it for translation again.

I found that these two safeguards more than compensated for the fact that the generated strings file are really source code, since they contain essential information for ibtool to translate properly.

Summary

Since everything happens at compile-time, my solution has none of the drawbacks of Wil’s solution:

  • No extra code needed.
  • You can look at a generated xib file in Interface Builder and immediately see any layout issues you might have. In this case, change the English xib, rebuild and check again.

Remember, these files should be added to version control, but not to your app bundle:

  • English.lproj/MainWindow.strings
  • English.lproj/MainWindow.xib
  • French.lproj/MainWindow.strings

And this file should be added to your app bundle, but not to version control (since it is generated each time):

  • French.lproj/MainWindow.xib

Now, every time you build, you will generate your French interface and it will be added to your app. Simple and efficient.

Categories: Development, MacOSX Tags:

C4[3]: Each decision is an opportunity to fuck up

September 30th, 2009 8 comments

I was fortunate enough to attend the fourth edition of the C4 conference in Chicago, September 25th to the 27th.

Synopsis

C4 is a developer conference, oriented towards Mac and iPhone independent (“indie”) developers.

The talks are intended to get you out of your comfort zone, and to expose you to new ideas. To make you think about a new way to explore problems.

This year, several BlitzTalks were presented. These talks are five minutes long and have 20 slides, auto-advancing every 15 seconds. It is fair to say that the BlitzTalks stole the show and were very appreciated by the audience. It was obvious that a lot of craftmanship went into each of those bite-sized talks.

I gave a BlitzTalk at C4[3], which was titled “Friction-free documentation” and was very well-received. I have included it in this post for completeness’ sake, because I obviously did not take notes during my own talk.

Juxtaposition
One of the funnier, and probably coincidental, aspect of this year’s C4 was all the contradictory advice that was given. For instance, “you should have a web form for contact info” (Aspeslagh) vs “You should never have a web form” (Welch). Or “Don’t use private APIs” (Drance) to “Here’s how to load a plugin in 64 bits now that Input Managers are gone” (Morrisson). Or “JSTalk is the future. Applescript is dead” (Rentzsch) to “You should always have an AppleScript interface” (Correia).

After all, the conference was exciting, thought-provoking and insightful. The food was excellent, and a lot of beer was drunk.

Apologies in advance…

This is my account. It has my biases. I may have summarized things in my own words, this is not verbatim. For that, you will have to wait for the videos.
I took quite a few notes, but some talks just did not lend themselves to note-taking. For example, Mark Boszko’s excellent “Video and You” was, well, very visual, and I don’t draw that fast.
It was especially hard to take notes in the BlitzTalks, they were, as Mike Ash put it, “like a shotgun blast to the frontal lobes, in a good way“.

So this is a transcription of my notes. There are probably some errors in there; if you see some please let me know and I will gladly fix them.

And if I did not capture your talk fully, or at all, that can also mean that I was so absorbed by it that I could not take notes.

I do have a special apology for Marshall Culpepper. I do not have any notes from his talk about Appcelerator, but the only reason is that I was physically drained from giving my BlitzTalk, which felt like giving a 30-minute talk in 5 minutes. That’s a lame excuse, but it’s the only one I have.

Full-length talks

Rentzsch – JSTalk

JSTalk is a language with optional bracket syntax, so it is easily accessible to both Obj-C and Javascript developers

One will note that JSTalk is intended for Desktop applications, while Objective-J (see 280North.com) is intended for Web apps.

JSTalk contains a framework, an optional editor and a command-line tool. You can add JSTalk support to your app with one line of code: [JSTalk listen]. This exposes your classes and object model in much the same way that FScriptAnywhere does. No need to write an object model wrapper like you do for AppleScript.

Benefits: fast and easy to do
Drawbacks: everything is exposed, nothing is documented unless you have sample code.

Note that you can save a JSTalk script as a truly stand-alone applet, as the script bundle can contain the JSTalk framework, which is pretty small.

Finally, JSTalk isn’t really about Javascript, it’s about scripting over Distributed Objects. Because that’s really what’s going on behind the scenes, as opposed to AppleEvents.

http://github.com/ccgus/jstalk

Drance – How to be a Good Developer

Matt Drance was a developer at Apple, moving from DTS to System Software. He became indie a few weeks ago and would like to share, from the inside, how to be a Good Developer™.

First, you must have and cultivate your contacts at Apple. To do this, it helps a lot if you make great stuff.
Find your focus, and polish that application. Don’t be shy, do some marketing and it will attract Apple’s attention. Get listed on MacOSX downloads: it’s free!.
Adopt Apple technologies early and often. Submit to the ADA: you may not win, but some smart and influential people will look at your application.
Go to Apple Events as much as you can. WWDC is not mandatory every year, but don’t avoid it either. If there are TechTalks or kitchens in your area (or relatively close), try to attend as much as possible.
When you have contacts at Apple, stay in touch. Sending promo codes to Apple employees is a great way to do this.

Information, Organization and Diplomacy

Information

Log bugs! If it’s not in Radar, it does not exist. Never assume that Apple knows.
Try to log good bugs. For the title, think keywords: ER (enhancement), REGR (regression), 10A342 (build number).
Note: bug titles are editable, so make sure that this information is also in the description.
More info is better. Shark samples are very useful.
If you can, attach the smallest sample project that reproduces the issue. A screen recording is also a very good way to explain a problem: more often than not, an engineer will look at a screencast and think: “I know exactly why this is happening”. This is good.
Think big! There may be a larger perspective here. You don’t know who else can be affected by this, might be thousands.
Your Enhancement Request can make Apple products better. For instance, the overlay controls in the iPhone camera were originally an ER for putting mustaches in front of people’s faces. Now they are used for Augmented Reality apps on the iPhone.
Duplicates happen, but they are important in weighing a bug. A good bug might also contain more info and help pinpoint the problem.
Answer your bugs. You may disagree politely (for instance “as designed”). Be civil, but you can also ask that it may be converted to a feature request. Make sure that documentation bugs are marked as such, as they are on a different track / release schedule.
If the Next Major OS release is not soon enough, you can request a Clone for Software Update. No guarantees, of course.

Get organized

Your elevator pitch for your bugs should always be ready. You should know your bug numbers: keep a prioritized hitlist / wishlist, complete with bug numbers. If it is a clear, brief and forwardable document, and you send it to a contact at Apple, it has a good chance of being passed around.

Diplomacy and Trust

It is very important to establish trust. Assume things are under NDA. If unsure, ask. Keep things quiet: don’t blab about next releases, and the possible fixes in them.
If you see one of your Apple contacts listed in the press, on a blog, something, tip them off.
Don’t name names: poorguy@apple.com may not have been supposed to help you!
Stick to the public API. Private APIs will break the trust you spent years building up.
Control yourself. Be fair in public, and firm in private. Be nice in Radar, and think before speaking.

Overall, stay positive and friendly. Apple is made of humans too!

Dribin – Unit Tests

System Tests

These tests are difficult to automate. They are usually slow. This is often your UI.
Several solutions exist for this (e.g. Eggplant) but they tend to be very high-maintenance.
You are better off having good QA people, and beta testers.
System tests often don’t do well with edge cases, because they are so rare.

Functional Tests

These tests can be fully automated, or launched on-demand (e.g. nightly). They tend to test several areas in-depth (ex: file I/O).
They can be relatively slow, their time is counted in minutes. 20 minutes is not unusual.

Unit Tests

These tests are very, very fast. So fast that you could run them at each compile and not notice. His app has over 200 unit tests and they run in less than a second.
Unit Tests are always automated, repeatable and self-checking (meaning that they report failures in a standard manner, be it a build break or an exit code).
Unit tests should not talk to a database, the network, the file system, or require a special setup of your environment.
UTs rely a lot on fake (mock) objects. For example. Core Data has the option of an in-memory store which is blazingly fast because it is not serialized to disk on every transaction. That has limited uses in the real world, but for Unit Tests it is essential.

Benefits include regression testing (did I break something that worked 5 minutes ago?), the ability to refactor, code that is cleaner and easier to maintain. It also allows testing hard-to-run conditions (what if that counter was 40,000?) and helps pinpoint the locality (scope) of errors.
Tests are often used as sample code, and so promote faster development.

Refactoring is improving your design after it has been written, in order to make your software easiter to understand. It will help you find bugs, and program faster, but to do that you have to have good unit tests.

Note that the MVC pattern in general makes code easier to test (see the Delegate pattern), but watch out for huge, all-encompassing controller classes.

Wayer – Translucent databases

What if you had a database of truly anonymous data?

Note that most americans can be uniquely identified by age, sex and zip code. Scary, huh?

If you remove the root user, you push the security to the edge, to your users: they have to remember their passwords since what is stored in the database is a hash combining their name and password. That way, if the database is compromised, no private information is divulged.

You may run the names through a simplification function first (e.g. ALLCAPS, no spaces) to help with entry name variation.

If you do not have a password-recovery system (and you may not have one, it is acceptable) you may have to throw away data, make a new account. This might be acceptable (e.g. throwaway email accounts) or not (bank / health records).

Welch – Carrot and the Stick

What to do when your users are angry at you.

Listen to your users: they have something to say. As long as they are talking to you, they are still passionate about your product. This is good.
Even if they use profanity, they still are professional.
Communication is a two-way street. Engage your users with modern means of communication. You can even call them: they will listen. Don’t have a simple web form as the only way to reach you.

Don’t tell them what to think. “Not a bug, but a feature” is not the correct response.

Your users are human, too. And if they can feel that you are human, that will go a long way.

Don’t try to cater to every user. If you honestly can’t do a certain thing, because you either can’t or there is no business case for it, tell them. And maybe recommend another product. You will make two people happy: the user who wanted to buy your product (but won’t) and the other company whose product you recommend. And you have not lost anything: it’s not money you would have had anyway. But this kind of honesty tends to come back in terms of trust, especially for future products.

Finally, there are two classes of users whom you may ignore, because the insignificant amount of money you will get from them pales in comparison to the time that they will cost you.

The New Media Douchebag can be totally ignored. The Scobles, Winers and Arringtons pretend to wield a lot of power but in fact they do not. Don’t be intimidated by them. They are a fickle bunch, and if you start to kiss their ass they will love you until the next shiny thing comes around, which may be tomorrow. And then you will have kissed ass for nothing.

The blogloon can also be ignored. But make sure that beneath the bile that they are trying to spread there is not a valid issue. Because blogloons typically don’t express their ideas clearly, good things can be lost in the noise. But once you have identified their issue (if there is one), you can ignore them.

Fackler – DVCS internals

Augie Fackler wrote and maintains hg-subversion, the premier hg interface to svn. He had the following tidbits of information regarding the lesser-known DVCSs.

Darcs was written by a physicist, in Haskell, over the principle of commutable patches. With those patches, you are essentially transforming your source tree from one version to another using a transform function, which is reversible. While seductive in theory, it turns out to be extremely slow in practice (on non-trivial source trees). Plus did I mention that you have to install a Haskell compiler?

Monotone is so security-conscious that every patch is signed, to the point that if you remove a patch in the middle of a chain, every subsequent patch has to be re-signed, in order, by the original signers. This is a big deal for most organizations, as people come and go all the time and key management becomes a nightmate.

BitKeeper was the premier DVCS system, until the point where a smart kernel hacker realized he could telnet into the database, run a few commands and get a full dump with history. BK were so irate that they pulled their Open Source licenses for kernel development, and Linus had to write git (but that’s another story all in itself).

Modern DVCS are fast and work offline as well as online. They are very efficient for storage, and make revisionist history obvious. It is easy in CVS and possible in SVN to go back and change files & history in an undetectable manner. Not at all with DVCSs, which store md5 hashes of every change, making it easy to detect reporsitory corruption and tampering.

The two main modern DVCSs are Git and Mercurial.

http://progit.org/book/ and http://hgbook.red-bean.com/read/ are the two books that are online. Both are good content.

Lloyd – Cocotron

Cocotron is an open-source, liberally-licensed project to port Cocoa to Windows. It is similar in intent to GnuStep, but has two big advantages.
First, it runs natively on Windows. No need for a “Yellow Box” or a reboot.
Second, it does not use the GPL LGPL license.

Cocotron started at about the same time as GNUStep, right after the publication of the OpenStep spec in 1994. It was not open-sourced until 2006, when it became possible to do so in part because of the Xcode developer tools.

Cocotron does not have native controls. Everything is custom-drawn.
Implementation is surprisingly efficient: Foundation relies on ~160 native OS calls, while AppKit has ~200 OS calls.
In graphic terms, CoreGraphics is a wrapper for the native drawing functionality. A project called Onyx 2D plans to implement the complete, native CoreGraphics suite in the near future.

You can build Cocotron using cross-compilation in Xcode. There are modified versions of binutils, for example -F / -framework options are added to ld, gcc and gdb are also modified. Xcode plugins are available.
Cocotron looks like a compiler to Xcode, accessible through build rules. It requires MinGW and the System headers/libs for the target system.

Remote debugging of the Windows executable is possible from gdb on the Mac, and should be possible with a VM though Christopher had no first-hand experience in this.

Lopp (aka Rands) – Talking shit, delegating and knowning what you want

When you do a presentation, have an arc, and three points.

For this presentation, the arc is that software development is a series of small decisions. There are of course large decisions, but these are more milestones than the small, day-to-day decisions that we continually make: “what will I name this variable? this class?” etc.

The milestones: Holy Shit, We could do this, We’re doing it, I’m screwed, We’re screwed, Glimmer of hope, Actual hope, Done.

Three points

Skills: talking shit (see Jerk City. Or don’t. Rands disavows any knowledge of this.)

You have to develop your comedy skills. It’s the art of improvisation. With time, this will become less about the funny and more about the “quickly parse everything you know and find the best answer.” Rands believes that all geeks are extremely good at this, even though they may not show it.

Delegate:

We are all control freaks. We like to detect the system to figure out its rules so that we can win. And winning is good. Only problem is we’re all very bad at something, which we may or may not be aware of. It may be graphic design. Maybe finance. Or managing a group of people to get them to do what you want. What do we do then?
The simple answer is to improve. We’re so bad at this skill that if we work at it, we can improve it and it will be better. And that’s often a good idea.
The better idea is to delegate: find someone who’s a rock star at that skill you suck so badly at. But to do that, you have to trust that others an help you. Which is difficult since you’re a control freak, remember?

Each decision is an opportunity to fuck up.

Knowing what you want.

This takes a shit ton of work. It goes from “Holy shit!” to knowing every. single. fact. ever. about something, and building your confidence about this subject. You may be a font nerd who cringes when he sees Arial, or a graphic design nerd, or a color nerd. But Knowing What You Want allows you to push all the decisions as early as possible

[Note: I'm not sure I agree that Big Design Up Front, which was touted by Rands, is the most appropriate method, but it is certain that the earlier you make the decisions, the better your product will be. Kind of like doing the riskiest things first.]

Using your new skills

This will help you make decisions in a crisis, and will give you leverage when negociation comes around. Because who wants to make compromises? Knowing what you want gives you measure, structure, direction.

Thomson – MacRuby

Objective-C is great, but it is not modern. It lacks several features of newer languages.

Code reuse could be much better. Single inheritance is often a barrier. For instance, the Singleton design pattern implies lots of boilerplate code. Who wants to write boilerplate code? Modern languages use either multiple inheritance (ugh!) or mixin classes.

Safety is limited. C is powerful at the price of safety. Raw pointers are often a major source of problems. Garbage collection means one less thing to worry about when writing the code you really care about.

Syntactic abstraction. Why is it necessary to declare an NSArray? Why aren’t hash tables part of the language? Things are getting better, slowly (e.g. foreach loops).

MacRuby is not a bridge to Cocoa. It is a first-class citizen in Cocoa, with complete access to all the frameworks. It is as fast, sometimes faster than Obj-C when dispatching methods. It has IB and debugging support.

When you use MacRuby, you get all the power and flexibility of a modern language. MacRuby boasts the first Ruby pre-compiler, which explains why it is so fast.

However, like all duck-typed languages, you sacrifice static type safety when you use MacRuby. That may be an issue for you, but years of Objective-C have shown that programs are fairly resilient to those dynamic issues.

Blitz Talks

Rhyne – Briefs

Briefs is a small application framework that allows you to create simple mockups for the iPhone, directly on the iPhone. It is also possible to create a fairly complex application that way. Perfect for elevator pitches. Check it out at http://giveabrief.com.

Aspeslagh – Full Time

Going indie full-time can be a lot of work. You have to automate your workflow as much as possible. Don’t manually authorize every sale, for instance.
When you build your store, assume you have more than one product. This will help tremendously when growing,
Have a support form, and (if possible) a support person. Get a virtual phone number.
Diversify your portfolio: people who buy one of your products are already predisposed to buying another one, especially if the experience was positive.

Bobtiki – Filming and photographing

Check out HowTube.com, and http://github.com/atebits/ for SimFinger, screencasting for the iPhone.

Speirs – One-man band

http://ecorner.stanford.edu is a great learning resource for things, even non-programming-related. Fraser learned all he knows about business and marketing from these free courses.

Czerniak – Security tools

CrashWrangler is a great tool from Apple to help you analyze crashes.
Dtrace for analysis. Good paper to read is Beauchamp & Weston.
RE:Trace
PyDbg is a Python debugger.

Vazquez – App Categories

Apps on the iTunes store can be categorized in multiple ways. Here are three of them, along with the observation that you can charge a fair price for some of those apps without too much difficulty.

Quick Hit – Twitter, email
Immersive – games
Accessory – subordinate to main activity. For instance, a guitar tuner is subordinate to playing guitar.
You are marketing to a group of enthusiasts that care about quality. There is no race to the bottom for 0.99$: you can charge a good price if your application is well done and polished.
Example: people that pay 10,000$ for a saxophone will not mind paying 800$ for a case if it is the best, toughest, lightest case out there.

Correia – AppleScript Matters

Your application’s scripting interface matters, because there are a lot more scripters out there than you think. And they will think up ways of using your app that you never thought of.
Your scripting interface is your UI, for scripters. It does not have to be pretty, but it has to be consistent.
Especially with AppleScript. Learn AS and its idioms, and adopt them in your scripting interface. For example, don’t do “do new window” (one commanr) where “create new window” (verb, qualifier, noun) is the accepted idiom.

You should design your scripting interface along with your object model. Cocoa makes this easier than you think.

Benefits include connections with thousands of other apps out there, and Automator, the Scripts menu, etc.

Casgrain – Friction-free documentation

The Blank Page syndrome

“Where to start?” can be paralyzing. Coders’ “blank pages” usually have some scaffolding

Help reduces your Tech Support. Time spent on Tech Support is time not spent on developing your app. Having the user help herself is always faster than email. Writing Help will pay for itself many times over.

Tech Support staff can double as Technical Writers. Definitely worth it on a larger app, but not if you’re just getting started. Hiring someone leads to management/synchronization issues, so friction.

Keep It Simple

Help is just HTML, so you could hire a web designer for your css instead of making one yourself.

Help is just a localizable folder. Users expect to find Help in the Help menu (Spotlight-searchable). Do you like writing html? Go nuts! It’s essentially Safari in a top-window. Don’t overcomplicate things for now
It’s easy if you’ve never done it. Don’t worry about structure: all the html files could be in the same folder.

Resist the urge to write a pdf. It won’t be searchable, and in most cases will open in a separate app (Preview) unless you do something clever. Don’t do it, it’s a time sink and you will tend to sweat the details.

Writing Help should be Friction-Free

What tool do you currently use to capture text? Text Editor? Snippet editor? Wiki?
Outliner?

Avoiding the Blank Page

It should be easy to lay down new thoughts with your tool. No need to create a new document per page. Auto-save is great. You should have minimal structure: titles, lists, maybe bold / italics. Automatic linking between sections if you can get it. I use VoodooPad.

Integrating Help in your Dev Tasks

Think of Help as a Unit Test: document the feature, how it should work, then write the code for it. Don’t sweat the details just yet (no screen grabs!); it’s all “code” for now. Spell-check is your friend.
One page per feature is a good rule of thumb. Spell-check is invaluable, as this “code” is not compiled but interpreted by humans. IT IS NOT A FEATURE SPEC.

Just like code, you will throw some of it away, but less than you might think. Also why it’s important to avoid putting images in your documentation when you start: those can be expensive to re- create.

Integrate Help in Version Control

Sometimes simpler is better (we like to diff) Pure text, Markdown, HTML, XML, RTF, VoodooPad, OmniOutliner…

Help should be a first-class resource in your app, just like the app icon and MainMenu.xib. Make sure it lives where your resources live.
Integrate Help in your build using Shell script build phases. Automate, automate, automate… For instance, you could automatically convert Markdown to HTML.

On-line help is seductive

Just a couple of stub html files, and you’re ready to go (_target=“blank”, anyone?). You can change the content without updating the whole app

Don’t do it unless your app depends on being on-line, since Help becomes dissociated from your app (you broke your version control). Plus your server infrastructure must be kept alive. It’s a great way to procrastinate: “I’ll do it after I ship the app…”
Version Control is broken, unless you do something clever in which case you’re just procrastinating

Example: iChibi http://apps.casgrain.com/iChibi

Godwin-Jones – Opacity

Opacity is a Quartz-based, vector image editor that specializes in icons. It can save to a variety of formats using factories, most interestingly as NSView subclasses and HTML5 <canvas> objects for quick prototyping. Highly recommended.

Hess – Cocoa Boutique

Cocoa Boutique is an open-source, in-app purchase for your app. It uses Aquatic Prime for the licensing, and php/mysql/paypal for the back-end processing.
It has not been written because Wil Shipley is greedy (Golden-Braeburn). The Potion Store is also good but runs on Rails.

http://github.com/fraserhess/boutique

Mitchell – PyObjC

It is a scripting bridge from Python to Objective-C. You can import most Cocoa frameworks directly into python.
For developers, the language is faster / easier than Applescript.
You can debug it with pdb.
ipython gets you an interactive AppKit shell.

Morisson – Loading plugins in 64 bit applications

[I have no notes for this because I was too absorbed by the presentation.]

Wood – Marketing

The “Google Keyword Tool” helps you fine-tune your title and meta-data to rank better in Google. In general, limit your to 65 characters and your <meta> to 156 characters.<br /> Try to link yourself to your products (from a blog or your main page or something) using descriptive text, because Google indexes the link, as well as the text that generated the link. Don’t use “Click Here” as your hyperlink text.</p> <p> Look for the Google Website Optimizer, it is full of good tools to help you make the most of your website by tracking where your users go and what helps them to buy your product.</p> <p> Have an email list with an incentive to join (eg freebie app, more templates for your app). Send good content to that mailing list so your users stay subscribed. When the time comes to announce a new product, do it on the mailing list and your users will help you with your marketing, because most of the time you give them valuable content for free, so they don’t mind (and in fact appreciate) the occasional marketing message.</p> <p> These users are very good: work to keep them. They are predisposed to liking your product, and maybe recommending it to friends. That kind of marketing cannot be bought, it has to be earned.</p> <p><h4>Gerbarg – Compiler engineering</h4> <p> So you found a bug, and you think the compiler is generating bad code. There are good news and bad news.<br /> Bad news: gcc’s code is old and scary. It is very hard to go in there and find, much less fix issues. Few mortals can do this.<br /> Good news: 90% of the issues are in the front-end parser, and Apple has just released (Open Source) a new tag-team: clang/llvm.<br /> <s>Clang is the static analyzer and llvm is a gcc front-end.</s> clang is a compiler front-end, while llvm is a low-level virtual machine which <a href="http://llvm.org/docs/CommandGuide/html/llvmgcc.html">can also generate native code</a>. They are written in easy-to-read, easy-to-maintain C++.</p> <p> You can subscribe and submit patches to the cfe-dev mailing list.<br /> You can check out the code from svn for clang-llvm and build it with current tools: congratulations, you have built your own compiler!</p> <p> Louis said he was not a compiler engineer, having worked on the front-end only, and he was able in a few hours to create a patch to llvm that allows pushing and popping a stack of pragma warnings. In those few hours he also submitted the patch, got it approved and committed to the clang-llvm source tree. His contribution should appear in the next release of Xcode.</p> <div class="fixed"></div> </div> <div class="under"> <span class="categories">Categories: </span><span><a href="http://developer.casgrain.com/?cat=1" title="View all posts in Development" rel="category">Development</a></span> <span class="tags">Tags: </span><span></span> </div> </div> <div class="post" id="post-43"> <h2><a class="title" href="http://developer.casgrain.com/?p=43" rel="bookmark">Display std::wstring in Xcode using a Data Formatter</a></h2> <div class="info"> <span class="date">July 21st, 2009</span> <span class="author"><a href="http://developer.casgrain.com/?author=2" title="Posts by Philippe" rel="author">Philippe</a></span> <span class="comments"><a href="http://developer.casgrain.com/?p=43#comments" title="Comment on Display std::wstring in Xcode using a Data Formatter">10 comments</a></span> <div class="fixed"></div> </div> <div class="content"> <h2><code>std::wstring</code>: <a href="http://www.losingfight.com/blog/2006/07/28/wchar_t-unsafe-at-any-size/">unsafe</a>, but sometimes necessary</h2> <p>When dealing with cross-platform code, especially Windows, it is not uncommon to encounter <code>wchar_t</code> and its companion string class, <code>std::wstring</code>.</p> <p> Unfortunately, Xcode does not display these types natively. Yes, you can <a href="http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.01.txt">add this file to your <code>.gdbinit</code></a> file and then you will be able to type:</p> <p><pre> pwstring mystring </pre> <p> but what you really want is for the values to show up in Xcode’s variable display, and in tooltips.<br /> <br /> What you need is called a <a href="http://developer.apple.com/documentation/developertools/Conceptual/XcodeDebugging/600-Viewing_Variables_and_Memory/variables_and_memory.html#//apple_ref/doc/uid/TP40007057-CH9-SW24">Custom Data Formatter</a>.</p> <p> In this post, I will adapt Apple’s sample <code>wchar_t</code> data formatter and modify it to display <code>std::wstring</code> variables. I will also explain where you should put this formatter in Xcode 3.1.<br /> <br /> Complete source code is available on <a href="http://bitbucket.org/philippec/wchardataformatter/">bitbucket.org</a>, with a MIT license.</p> <h2>Initial Data Formatter</h2> <p>Xcode Data Formatters are simple <a href="http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFBundles/CFBundles.html">bundles</a> that are loaded by Xcode at startup. They are essentially plug-ins to extend Xcode.</p> <p> Starting with Apple’s own <a href="http://developer.apple.com/samplecode/WcharDataFormatter/">wchar_t Data Formatter sample</a>, we immediately notice that:</p> <ul> <li>This sample is quite outdated, almost 4 years old (the Release build actually builds only PPC!) <li>It won’t work as-is with <code>std::wstring</code> since it only contains .c files. </ul> <p>We will update this sample to work with <code>std::wstring</code> and build it as a 4-way universal binary.</p> <h2>Modernizing the Data Formatter</h2> <h3>Switching to C++</h3> <p>Since the data formatter will use <code>std::wstring</code>, we need to build it using C++. Just rename all the .c files to .cpp and voilà!</p> <h3>Modify CustomDataViews.plist</h3> <p>If you open CustomDataViews.plist, you will see that it has one entry per variable type that the formatter can handle. That entry contains a Data Formatter, much like the one you would type in Xcode itself (for example, to display the name of a notification—of type NSNotification—you can use <code>{(NSString *)[$VAR name]}</code>). <br /> What is different here is the formatter contains a string that calls back in our custom Data Formatter: for example, <code>wchar_t</code> corresponds to <code>{(char *)myWCharDataFormatter((wchar_t) $VAR, (int) $ID)}:s</code>. <br /> Add two entries to that plist, for types <code>wstring</code> and <code>wstring*</code>, and replace the callback strings with a new unique string, for instance <code>myWStringDataFormatter</code> and <code>myWStringPointerDataFormatter</code>. Watch for capitalization, case matters.</p> <h3>Add new callback functions</h3> <p>Now add the two callback functions you referenced in the plist in <code>myCustomFormatter.cpp</code>:</p> <pre> #include <string> char * myWStringDataFormatter(std::wstring wstr, int identifier) { size_t bufLen = wstr.size() + 1; return dataformatter_char_for_wchar(wstr.data(), identifier, bufLen); } char * myWStringPointerDataFormatter(std::wstring *wstr, int identifier) { size_t bufLen = wstr->size() + 1; return dataformatter_char_for_wchar(wstr->data(), identifier, bufLen); } </pre> <p>As you can see, we are re-using the preexisting <code>wchar_t</code> code with our <code>std::wstring</code>.</p> <h3>Build a 4-way Universal Binary</h3> <p>Double-click the wchardataformatter project icon to bring up the Project Inspector. Select the Release configuration, and click the “Architectures” pop-up menu. Select 32/64 bit universal, as shown below. <p> <img src="/images/wchardataformatter_universal.png" hspace="4" vspace="8" alt="Universal Architecture in Xcode"></p> <h3>Modify the Test Code</h3> <p>Finally, update <code>wcharTest_main.cpp</code> to add new <code>std::wstring</code> variables to display in the debugger:</p> <pre> #include <stdlib.h> #include <wchar.h> #include <string> int main(int argc, char *argv[]) { wchar_t c = 'A'; wchar_t b[255]; wchar_t *d = &b[0]; char *a = "a b c d e f g"; mbstowcs(d, a , strlen(a)); std::wstring s = L"wide string"; std::wstring *ps = &s; return 0; } </pre> <p>Switch the target to <em>wCharTest</em> in Xcode, set a breakpoint on the last line, and hit “Build and Go”. Xcode should build the test application and stop in the Debugger. Since you have not installed the formatter, you should not see anything special in the Variable Display window.</p> <h2>Installing the Data Formatter</h2> <p>Build the Data Formatter (Debug or Release). Locate the bundle by control-clicking on the “Products / wcharDataFormatter.bundle” in the Xcode project.<br /> Drag the bundle to this folder: <code>~/Library/Application\ Support/Developer/Shared/Xcode/CustomDataViews</code>, creating intermediate folders along the way if they do not exist.<br /> You can remove the ~ to install for all users (not just you), and you can also replace “Shared” in the path with “3.0″ or “3.1″ if you only wanted to install the formatter for Xcode 3.0 or 3.1.</p> <h2>Testing the Formatter</h2> <p>Build the <em>wcharTest</em> target, and set a breakpoint in the main() function of wcharTest_main.cpp. You can step over each line, and you should see your data formatter being called and displaying in Xcode’s Variable Display, as well as in tooltips (Xcode 3.1 and later).</p> <p><img align="center" src="/images/wchardataformatter_display.png" hspace="4" vspace="8" alt="Formatter Display in Xcode"></p> <div class="fixed"></div> </div> <div class="under"> <span class="categories">Categories: </span><span><a href="http://developer.casgrain.com/?cat=1" title="View all posts in Development" rel="category">Development</a>, <a href="http://developer.casgrain.com/?cat=5" title="View all posts in MacOSX" rel="category">MacOSX</a></span> <span class="tags">Tags: </span><span></span> </div> </div> <div id="pagenavi"> <span class="newer"></span> <span class="older"><a href="http://developer.casgrain.com/?paged=2" >Older Entries</a></span> <div class="fixed"></div> </div> </div> <!-- main END --> <!-- sidebar START --> <div id="sidebar"> <!-- sidebar north START --> <div id="northsidebar" class="sidebar"> <!-- feeds --> <div class="widget widget_feeds"> <div class="content"> <div id="subscribe"> <a rel="external nofollow" id="feedrss" title="Subscribe to this blog..." href="http://developer.casgrain.com/?feed=rss2"><abbr title="Really Simple Syndication">RSS</abbr></a> <ul id="feed_readers"> <li id="google_reader"><a rel="external nofollow" class="reader" title="Subscribe with Google" href="http://fusion.google.com/add?feedurl=http://developer.casgrain.com/?feed=rss2"><span>Google</span></a></li> <li id="youdao_reader"><a rel="external nofollow" class="reader" title="Subscribe with Youdao" href="http://reader.youdao.com/#url=http://developer.casgrain.com/?feed=rss2"><span>Youdao</span></a></li> <li id="xianguo_reader"><a rel="external nofollow" class="reader" title="Subscribe with Xian Guo" href="http://www.xianguo.com/subscribe.php?url=http://developer.casgrain.com/?feed=rss2"><span>Xian Guo</span></a></li> <li id="zhuaxia_reader"><a rel="external nofollow" class="reader" title="Subscribe with Zhua Xia" href="http://www.zhuaxia.com/add_channel.php?url=http://developer.casgrain.com/?feed=rss2"><span>Zhua Xia</span></a></li> <li id="yahoo_reader"><a rel="external nofollow" class="reader" title="Subscribe with My Yahoo!" href="http://add.my.yahoo.com/rss?url=http://developer.casgrain.com/?feed=rss2"><span>My Yahoo!</span></a></li> <li id="newsgator_reader"><a rel="external nofollow" class="reader" title="Subscribe with newsgator" href="http://www.newsgator.com/ngs/subscriber/subfext.aspx?url=http://developer.casgrain.com/?feed=rss2"><span>newsgator</span></a></li> <li id="bloglines_reader"><a rel="external nofollow" class="reader" title="Subscribe with Bloglines" href="http://www.bloglines.com/sub/http://developer.casgrain.com/?feed=rss2"><span>Bloglines</span></a></li> <li id="inezha_reader"><a rel="external nofollow" class="reader" title="Subscribe with iNezha" href="http://inezha.com/add?url=http://developer.casgrain.com/?feed=rss2"><span>iNezha</span></a></li> </ul> </div> <div class="fixed"></div> </div> </div> <!-- showcase --> <!-- posts --> <div class="widget"> <h3>Random Posts</h3> <ul> <li><a href="http://developer.casgrain.com/?p=102">Multiple developers, one iPhone app</a></li><li><a href="http://developer.casgrain.com/?p=3">Creating a Glow effect using Quartz Composer</a></li><li><a href="http://developer.casgrain.com/?p=14">Day One: Daylight</a></li><li><a href="http://developer.casgrain.com/?p=104">Eight guys, four weeks, one dream</a></li><li><a href="http://developer.casgrain.com/?p=115">Xcode 4.2 and older iOS devices</a></li> </ul> </div> <!-- recent comments --> <!-- tag cloud --> <div id="tag_cloud" class="widget"> <h3>Tag Cloud</h3> </div> </div> <!-- sidebar north END --> <div id="centersidebar"> <!-- sidebar east START --> <div id="eastsidebar" class="sidebar"> <!-- categories --> <div class="widget widget_categories"> <h3>Categories</h3> <ul> <li class="cat-item cat-item-1"><a href="http://developer.casgrain.com/?cat=1" title="View all posts filed under Development">Development</a> </li> <li class="cat-item cat-item-3"><a href="http://developer.casgrain.com/?cat=3" title="View all posts filed under Graphics">Graphics</a> </li> <li class="cat-item cat-item-9"><a href="http://developer.casgrain.com/?cat=9" title="View all posts filed under iOS">iOS</a> </li> <li class="cat-item cat-item-5"><a href="http://developer.casgrain.com/?cat=5" title="View all posts filed under MacOSX">MacOSX</a> </li> <li class="cat-item cat-item-7"><a href="http://developer.casgrain.com/?cat=7" title="Quick Tips">Quickie</a> </li> <li class="cat-item cat-item-10"><a href="http://developer.casgrain.com/?cat=10" title="View all posts filed under Xcode">Xcode</a> </li> </ul> </div> </div> <!-- sidebar east END --> <!-- sidebar west START --> <div id="westsidebar" class="sidebar"> <!-- blogroll --> <div class="widget widget_links"> <h3>Blogroll</h3> <ul> <li><a href="http://borkwarellc.wordpress.com">Borkware Miniblog</a></li> <li><a href="http://wilshipley.com/blog/">Call Me Fishmeal.</a></li> <li><a href="http://chanson.livejournal.com/">Chris Hanson</a></li> <li><a href="http://gusmueller.com/blog/">Gus’s blog, adventures in Flying Meat.</a></li> <li><a href="http://www.latenightcocoa.com/" title="Mac Development Podcast">Late Night Cocoa</a></li> <li><a href="http://www.red-sweater.com/blog">Red Sweater Blog</a></li> <li><a href="http://rentzsch.com">rentzsch.com: Tales from the Red Shed</a></li> <li><a href="http://theocacao.com/">Theobroma Cacao</a></li> </ul> </div> </div> <!-- sidebar west END --> <div class="fixed"></div> </div> <!-- sidebar south START --> <div id="southsidebar" class="sidebar"> <!-- archives --> <div class="widget"> <h3>Archives</h3> <ul> <li><a href='http://developer.casgrain.com/?m=201202' title='February 2012'>February 2012</a></li> <li><a href='http://developer.casgrain.com/?m=201112' title='December 2011'>December 2011</a></li> <li><a href='http://developer.casgrain.com/?m=201009' title='September 2010'>September 2010</a></li> <li><a href='http://developer.casgrain.com/?m=201008' title='August 2010'>August 2010</a></li> <li><a href='http://developer.casgrain.com/?m=201002' title='February 2010'>February 2010</a></li> <li><a href='http://developer.casgrain.com/?m=201001' title='January 2010'>January 2010</a></li> <li><a href='http://developer.casgrain.com/?m=200912' title='December 2009'>December 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200909' title='September 2009'>September 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200907' title='July 2009'>July 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200906' title='June 2009'>June 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200905' title='May 2009'>May 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200904' title='April 2009'>April 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200902' title='February 2009'>February 2009</a></li> <li><a href='http://developer.casgrain.com/?m=200809' title='September 2008'>September 2008</a></li> <li><a href='http://developer.casgrain.com/?m=200807' title='July 2008'>July 2008</a></li> <li><a href='http://developer.casgrain.com/?m=200805' title='May 2008'>May 2008</a></li> <li><a href='http://developer.casgrain.com/?m=200803' title='March 2008'>March 2008</a></li> <li><a href='http://developer.casgrain.com/?m=200802' title='February 2008'>February 2008</a></li> </ul> </div> <!-- meta --> <div class="widget"> <h3>Meta</h3> <ul> <li><a href="http://developer.casgrain.com/wp-login.php">Log in</a></li> </ul> </div> </div> <!-- sidebar south END --> </div> <!-- sidebar END --> <div class="fixed"></div> </div> <!-- content END --> <!-- footer START --> <div id="footer"> <a id="gotop" href="#" onclick="MGJS.goTop();return false;">Top</a> <a id="powered" href="http://wordpress.org/">WordPress</a> <div id="copyright"> Copyright © 2008-2013 developer.casgrain.com </div> <div id="themeinfo"> Theme by <a href="http://www.neoease.com/">NeoEase</a>. Valid <a href="http://validator.w3.org/check?uri=referer">XHTML 1.1</a> and <a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3">CSS 3</a>. </div> </div> <!-- footer END --> </div> <!-- container END --> </div> <!-- wrap END --> </body> </html>