Hunting down crashes in an iPhone app often involves uncaught exceptions. Even if we’re running from the debugger at the time, the crash happens after the exception is thrown, so the only entries shown in the debugger’s stack are from the exception catching code.

We do get a printout of the stack at the time of the exception but it’s a numeric stack trace so we’ll need to use the atos command line utility to make sense of the numbers. Here’s an example of a crash in a development build of Tomatoes:

2008-08-01 21:10:20.138 Tomatoes[151:20b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds'
2008-08-01 21:10:20.213 Tomatoes[151:20b] Stack: (
808163835,
806099672,
807978623,
807978527,
812533155,
812164939,
812716685,
22067,
35325,
812317455,
812317325,
824032771,
824024301,
824022997,
807779567,
807777675,
829004012,
816177936,
816214500,
8381,
8244
)
terminate called after throwing an instance of 'NSException'
kill
quit

We’ll need to call atos for each stack entry and we’ll need to know the path to the app on disk: In Xcode right click on the app under Products and select ‘Reveal in Finder’, then right click on the app in the Finder and select ‘Show Package Contents’, find the executable and drag it to the Terminal window to get the path.

The entries in the stack that belong to our app will be have smaller values. In this case 22067 and 35325. So let’s see what we have:

atos -o /Users/pboctor/iphone/Tomatoes/build/Debug-iphonesimulator/Tomatoes.app/Tomatoes 22067
-[NSObject(MovieUtils) stripHTML:] (in Tomatoes) (MovieUtils.m:55)

atos -o /Users/pboctor/iphone/Tomatoes/build/Debug-iphonesimulator/Tomatoes.app/Tomatoes 35325
-[RottenCurrentMoviesTableController connectionDidFinishLoading:] (in Tomatoes) (RottenCurrentMoviesTableController.m:482)

It looks like after we’re done downloading some data, we call stripHTML and then crash while trying to replace some values in a string. Off to fix some code!

One final thing: If the numeric stack trace came from the app while running on the iPhone and not in the simulator, then we need to tell atos the proper architecture of the executable:

atos -o /Users/pboctor/iphone/Tomatoes/build/Debug-iphoneos/Tomatoes.app/Tomatoes -arch armv6 22067

Happy bug fixing.

To copy the list of installed printers from one machine to another, copy the following files:

/etc/cups/printers.conf
/etc/cups/printers.conf.O
/etc/cups/ppd/*
~/Library/Printers/*
~/Library/Preferences/com.apple.print*

Make sure the files in /etc/cups retain the proper owner and group (root:_lp) and permissions (‘u=rw,go=’for the conf files and ‘u=rw,go=r’for the ppd files).

You’ll also have to re-install any printer drivers that you installed on the old machine.

Restart after you’re done and System Preferences -> Print & Fax should now show your printer list.

After installing Leopard and restarting, Migration Assistant offers to transfer your data:
Leopare Migration Assistant

If I chose “from another volume on this Mac” (connected via USB) or “from another Mac” (connected via Firewire disk mode), I’d immediately get one of these errors:

  • “Mac OS X was not found on the volume you selected.”
  • “There are no version of Mac OS X on your old Mac.”
  • “You can only transfer information from a Mac that has OS X installed.”

The error comes right away, before I actually selected anything. The drive booted without any problems either.

So here is the very non-intuitve fix in case any one else runs into the same problem:

  • When the error comes up, just let it sit there for a while (a good 10 minutes in my case).
  • You’ll then start to notice that the information from your drive/machine starts showing up (Account info, size of the Applications folder, etc)
  • After all the information is populated, click Cancel in the dialog box which will take you back to the previous screen.
  • Select “from another volume on this Mac” or “from another Mac” again and this time there will be no error.

Inspired by DRY up your views (slides) at last week’s RailsConf, I’m trying to improve a view that contains far too much code.

The view needs to display a menu of tasks. Whether and how each task is displayed depends on a combination of the current user’s rights as well as what they had done previously.

With a big block of code for each task, the view file quickly became a mess:


<div>
  <ul class='menu'>
    <% if current_user.has_right_for?('foos') %>
      <li>
        <% if current_user.foo %>
          <%= link_to 'Stop Foo', foo_url, :method => :delete %>
        <% else %>
          <% form_tag(foos_url, :name=>'add_foo',
                      :style=>"margin:0;padding:0;display:inline;") do %>
            <%= hidden_field_tag :bar_id, @bar.id %>
            <%= link_to_function "Start Foo", "document.add_foo.submit()" %>
          <% end %>
        <% end %>
      </li>
  </ul>
</div>

OK, so let’s move each task into a helper:

<div>
  <ul class='menu'>
    <%= start_or_stop_foo -%>
  </ul>
</div>

def start_or_stop_foo(tag='li')
  if current_user.has_right_for?('foos')
    content_tag(tag, link_to('Stop Foo', foo_url, :method => :delete))
  else
    content_tag(tag) do
      form_tag(foos_url, :name=>'add_foo',
                  :style=>"margin:0;padding:0;display:inline;") do
        hidden_field_tag :bar_id, @bar.id
        link_to_function "Start Foo", "document.add_foo.submit()"
      end
    end
  end
end

This unfortunately doesn’t work. Both content_tag and form_tag assume that you’re calling them from an action view template. A fix has been applied to edge rails for content_tag, but we need one for form_tag:

From form_tag_helper.rb, replace:

concat(tag(:form, html_options, true) + method_tag, block.binding)
concat(content, block.binding)
concat("</form>", block.binding)

with:

form_tag = tag(:form, html_options, true) + method_tag
if block_is_within_action_view?(block)
  concat(form_tag, block.binding)
  concat(content, block.binding)
  concat("</form>", block.binding)
else
  form_tag + content + "</form>"
end

def block_is_within_action_view?(block) 
  eval("defined? _erbout", block.binding) 
end

I don’t like patching Rails because it’s fragile. I have to remember to remove or re-apply the patch the next time I upgrade my Rails installation.

Is there another way of moving this code out of the view and into a helper?

Friday was my last day as an Adobe employee and as an InDesign engineer. I worked at Adobe for 12 years and on the InDesign team since well before we shipped InDesign 1.0.

During the first four releases of InDesign (1.0, 1.5, 2.0, 3.0 (CS)) I worked on InDesign scripting, exposing InDesign to AppleScript, Visual Basic and JavaScript.

During the 4.0 (CS2) release I worked on InDesign Server, removing all of the UI from InDesign so that it plays nice in the server world.

Adobe was a great company to work for. What a thrill it was to build a new product and see it evolve. Our users loved the product and enthusiastically helped us make it better.

I met a lot of great people at Adobe which I will miss but in the end, the entrepreneur urge was too strong.

I leave Adobe to start my own software company. I have some very exciting product ideas that I’ll be working on. I can’t wait to fill everyody in on the details!

Follow

Get every new post delivered to your Inbox.