Ben Scheirman

These fickle bits...

Menu

Making a UIButton Flip Over

If you’ve used the iPod app on the iPhone, you’ve probably seen an interesting trick when switching from album art to the track listing: the button in the top right corner flips over synchronized with the flip animation of the main view.

I wanted to achieve a similar effect for the iPhone app that I’m building, Deli Radio (app store link).

If you’ve ever struggled with the flip transitions before, you probably know how finicky it can be to get it all working. The best way to set it up is to have a parent view contain both views that you want to swap, and set the animation transition type on that view.

For a button (either in the navigation bar or elsewhere) we’d need to introduce a parent view to achieve this effect. This is how I achieved the effect.

First, I had two images I wanted to use for my UIBarButtonItem.

I wanted this to be easily reusable (since I need to do this in more than one place in this application), so I created a category method on UIButton.

It may look strange that a UIButton class method returns a UIView instance, but we need to have a container view to base the animations off of.

Here is the implementation:

I am using a little-known technique of setting associated objects using objc_setAssociatedObject(...). This uses the runtime to attach state to an existing class without needing to subclass.

Now that you understand how it is all setup, the block body will now make sense:

Usage is really easy. I just created a bar button item with a custom view, and was done.

1
2
3
4
5
6
7
8
9
10
11
12
13
UIImage *firstImage  = [UIImage imageNamed:@"btn-info.png"];
UIImage *secondImage = [UIImage imageNamed:@"btn-images.png"];
UIView *container    = [UIButton flipButtonWithFirstImage:firstImage
                                              secondImage:secondImage
                                          firstTransition:UIViewAnimationTransitionFlipFromRight
                                         secondTransition:UIViewAnimationTransitionFlipFromLeft
                                           animationCurve:UIViewAnimationCurveEaseInOut
                                                 duration:0.8
                                                   target:self
                                                 selector:@selector(flipContent)];

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
  initWithCustomView:container] autorelease];

The effect can be seen below.

Note that the flip effect on the main view is achieved separately, but the 2 strategies share identical values for the animation, so the flip transition types match, as well as the duration & animation curve.

The code for this can be seen in the ChaiOneUI project on Github.

Creating a Glow Effect for UILabel and UIButton

One recent iPhone design mockup called for a glowing effect for a UIButton.

This can be accomplished with images, however I needed a series of buttons to have the same glow effect, and it can easily be accomplished with Core Graphics.

The first step is to include the Core Graphics headers:

1
#import <QuartzCore/QuartzCore.h>

Next, the effect is achieved by using a shadow with no offset (meaning the shadow will be directly underneath the text, not shifted down or to the right). The layer is then given a shadow radius & opacity to allow the shadow to bleed outward. Unsetting masksToBounds will allow the glow to be drawn even outside of the label’s frame. Finally the shadow color is set to either the foreground color or something a bit lighter.

1
2
3
4
5
6
UIColor *color = button.currentTitleColor;
button.titleLabel.layer.shadowColor = [color CGColor];
button.titleLabel.layer.shadowRadius = 4.0f;
button.titleLabel.layer.shadowOpacity = .9;
button.titleLabel.layer.shadowOffset = CGSizeZero;
button.titleLabel.layer.masksToBounds = NO;

This effect works on plain UILabel or the titleLabel property of a UIButton. You can see the results of the effect here:

Don’t go overboard with this. It’s a subtle effect, but looks great when used effectively.

Introducing App Sites

I’ve not been that great about marketing Giggle Touch. It’s a cool app, kids like it, but most people don’t know about it.

The biggest reason was probably that I never set up a proper website for it. Doing a search would only yield a blog post that said it was “coming soon.”

That’s all changed now. I’d like to introduce App Sites.

App Sites

The premise is simple: standup a website for an iPhone app in minutes.

Check it out here: http://appsites.heroku.com.

You can see the site in action by visiting the Giggle Touch page.

It’s free (for now) and gives you the ability to add features, a description, a link back to the app, and a screenshot.

Planned upcoming features include:

  • Custom domains
  • Multiple screenshots
  • Videos
  • Coming soon (if the app hasn’t launched yet)
  • More analytics

If you have an iPhone app, I encourage you to create a page. Let me know what you think!

Firebug-Style Visual Debugging for iOS

Using a crazy helpful library called DC Introspect you’re able to easily take an app running in the Simulator:

And get visual frame debugging information like this:

You can also click & drag your mouse to get pixel information, surrounding frames, print out detailed frame information in the console, and even move frames around all while the app is running.

Using it is incredibly simple:

  • Make sure you have DEBUG defined in your Preprocessor Macros:

1
    #import "DCIntrospect.h"
1
2
3
4
5
6
7
// in applicationDidFinishLaunching:

[self.window makeKeyAndVisible];

#ifdef TARGET_IPHONE_SIMULATOR
    [[DCIntrospect sharedIntrospector] start];
#endif

Once that is done, the library will be loaded and you can use it. When the simulator launches, just press Spacebar to activate the tool.

Here are some keyboard shortcuts:

  • o – Outline all views
  • ? – Prints out a help view
  • f – Flash on drawRect: calls
  • c – Toggle showing coordinates
  • 4 6 8 2 – Nudge the selected view left, right, up, down
  • 0 – Recenter view where it was originally
  • 9 7 3 1 – Modify Width & Height of selected view

You can also click & drag with the mouse to get detailed information about frames & mouse position.

I am amazed at how awesome this library is. I’ll be using it in my default toolbox from now on.

Vim - Could Not Invoke JSLint

If you’re running MacVim with Janus and have upgraded to Lion, you may have noticed a little error when you open JavaScript files:

Error detected while processing function 87_JSLint: Line 33: could not invoke JSLint!

It seems many are having this issue. There are 2 things to check:

  1. Make sure you have Node in your path. Confirm this by typing which node and make sure it resolves a binary somewhere on your system.
  2. Open up your ~/.vimrc.local and add this command:
1
2
" Use Node.js for JavaScript interpretation
let $JS_CMD='node'

Kudos to eventualbuddha for figuring this out.

Is Rails Exempt?

If you’ve been following the Ruby community recently, you’d notice that there’s are people calling our Rails (and Rails developers) for treating Rails as if it is somehow exempt from long-standing software principles.

Roy Osherove, a fairly well-known .NET developer and author of The Art of Unit Testing, ventured into Ruby-land recently and commented on twitter about how Rails’s definition of unit & integration is quite different from his.

I have to agree with Roy. Those in the TDD camp in .NET understood the difference and were (from my experience) fairly cognizent of isolating concerns and not mixing the 2 concepts. Some even go as far as to isolate integration tests into their own assembly, providing a physical separation further guaranteeing that a unit test project won’t touch web services or the database.

It’s easy to assume from the outside that the Rails is just testing nirvana and that everyone does it and it’s so easy. Unfortunately it’s just not the truth. Rails (and Ruby) make testing really easy but that means it’s even easier to do the wrong thing as well.

Legacy Rails Apps

Now that Rails is (gasp) over 7 years old you’re starting to see some real legacy Rails applications out in the wild.

Avdi Grimm has a good post on the topic of how many of the Rails apps he comes to work on are in poor shape, technically.

Here are a few examples, just to give you an idea of what I’m talking about:

“Design Patterns are a Java thing. In Ruby you just write code.”

“The warnings Ruby produces are dumb; just disable them.”

“Sure they aren’t technically Unit Tests, but isolating objects turned out to be kind of hard and besides nobody else is doing it.”

“Stuff like the Law of Demeter isn’t really as important in Ruby code”

“That’s only a problem in large projects” (implying that this project will never become large).

I’ve certainly been guilty of some of this. Rails makes it easy to do things that can turn out to be problematic. As with anything, you have to be disciplined to notice the warning signs and act accordingly.

When testing is painful, you’re likely making mistakes. Some common pain-points that I’ve experienced are:

  • No tests – the app is hard to test because the design is poor. Classes are too tightly coupled and don’t have clear delineation of responsibilities.
  • Tests break for unrelated reasons – the tests are covering too much behavior, so when a single behavior changes, many tests break.
  • Tests break when implementation changes – the tests are probably utilizing too much mocking & stubbing. The tests are coupled heavily to a particular implementation.
  • Unclear what the problem is when a test breaks – Tests are probably too coarse-grained and may contain too many assertions per test.

These are just a sampling of what I’ve personally observed.

So why do many Rails developers ignore these concepts?

Pragmatism at work

Many rails tutorials (and the default Rails template) treats model tests as unit tests. Since Rails models are by default based on Active Record, they have data access baked into their core. Doing proper unit testing means you’re testing a logical unit. If your test involves a model operation that requires a database round-trip, that’s technically an integration test. But does it really matter?

Most Rails developers will tell you no. Consider this spec:

1
2
3
4
5
describe Post do
  it "should be initially unpublished" do
    Post.new.published.should == false
  end
end

This is a unit test. It tests a single piece of functionality and will fail for just one reason.

Now, here’s another example:

1
2
3
it "should fetch published articles" do
  # ?
end
1
2
3
4
5
6
# post.rb
class Post < ActiveRecord::Base
  def self.published
    where("published_at <= ?", Time.now)
  end
end

How should you implement this spec?

If you were trying to avoid hitting the database you might intercept the where call and assert the parameters passed to it. But surely this isn’t the only way you could implement this method giving the same behavior. You might use scopes or another where call might actually be added later that doesn’t affect the outcome of this method in any way that this test is concerned about.

1
2
3
4
5
6
7
it "should fetch published articles" do
  3.times { Factory.create :article }
  future_post = Factory.create :article, :published_at => 2.days.from_now
  posts = Post.published
  posts.size.should == 3
  post.should_not include future_post
end

This test hits the database (numerous times, in fact) but it’s testing exactly the behavior we need. We aren’t testing implementation, we’re testing that the behavior works as intended. If we somehow muck with the query, breaking it, this test will fail. If we change the implementation to use some other query means (scopes or whatever) this test will still pass.

Is it so bad that the test hits the database?

There are drawbacks of course:

  • The test requires a database, thus you have to migrate
  • The database_cleaner gem will have to be present to clean out the database before each run
  • These database statements make the test suite a LOT slower, so large test suites will eventually suffer.
  • The tests could fail if the database isn’t present (or migrated), or if the query is incorrect. But this isn’t likely to happen since we’re using a tested framework (ActiveRecord).

Ultimately this isn’t really a unit test at all. It’s an integration test. So is spec/models/post_spec.rb the wrong place for this stuff?

The question eventually comes down to this: What is more valuable? A fast, isolated test suite? Or a test suite that breaks for the right reasons?

Don’t throw out good practices just because it’s Ruby

I think it’s important to be cognizant of software paradigms and use them where they make sense. It’s also important to recognize when practices are being ignored because “celebrities” aren’t touting them.

It is still valuable, however, to keep a fresh eye on old assumptions. Don’t always take things as gospel just because that’s the way they have always been. One of the things I love about the Ruby community is how willing people are to rock the boat & try something new.

When viewWillAppear: Isn’t Called

The UIViewController lifecycle is pretty simple. viewDidLoad is called when the view is loaded (usually from a XIB) and when the view controller’s view is about to be displayed viewWillAppear: gets called (and viewWillDisappear: when it goes away).

The problem is, when you have a non-standard view hierarchy (like my current app) these methods don’t get called. The Apple docs have this to say about the problem:

Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.

In my application I have a persistent bar at the bottom of the screen, so my UINavigationController only owns a portion of the screen. Thus, my RootViewController (which owns these 2 portions) is always active.

I recently came upon a requirement that needed to leverage viewWillAppear: and viewWillDisappear: in order to decorate the bottom bar with some additional information. Since this is a view controller a few layers deep in the hierarchy, the methods weren’t being called.

Luckly, there is a fix to this. The navigation controller can notify its delegate when it changes view controllers.

Start off in the view controller that is the root of the navigation controller hierarchy. Make it conform to the UINavigationControllerDelegate protocol. We’ll also need an ivar to store the last view controller that appeared so that we can notify when it disappears.

1
2
3
4
5
6
7
@interface MyRootViewController : UIViewController
    <UINavigationControllerDelegate> {
      UIViewController *_lastViewController;
}
// methods

@end

In the implementation, in do the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    @implementation MyRootViewController

    // other stuff

    - (void)viewDidLoad {
        [super viewDidLoad];

        self.navigationController.delegate = self;
        // ...
    }

    - (void)navigationController:(UINavigationController *)navigationController
          willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        if (_lastViewController) {
            [_lastViewController viewWillDisappear:animated];
        }

        [viewController viewWillAppear:animated];
        _lastViewController = viewController;
    }

If you need support for viewDidAppear and viewDidDisappear then you’d have to implement this method as well:

1
2
3
- (void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animated;

After doing this, your view controllers should start receiving the viewWillAppear: and viewWillDisappear: methods successfully.

Moving My Blog

I’ve decided to transition over to a new blog.

The reasons? Mostly because I’m questioning more & more the need to have a dynamic blog that I need to maintain. Static HTML blog generators are very interesting and I thought I’d give one a try.

I’ll leave this one around for historical reasons. It gets a decent amount of traffic and has content going back to 2004.

So without further ado I present my new blog, Fickle Bits.

(Note to RSS readers, your feeds will not auto-update. Subscribe to the new blog here: Subscribe )

My Vim Journey

For my Rails work, I’ve largely leaned on TextMate. It’s used by many Rubyists, looks sexy, and is easily extended.

I still use TextMate frequently, but I’ve been ramping up on my Vim skills and I’ve recently come to a point where I think I’m pretty productive in it.

My initial frustrations with Vim were that it was too configurable. Talk to any Vim power-user and you’ll find a completely different set of plugins & keyboard shortcuts. If you snag a friend’s set of Vim configuration files (like I did) you might find yourself frustrated that there’s too much to learn and it’s difficult to know where various behaviors are coming from.

In this post, I’ll attempt to demonstrate a very sane Vim setup that newcomers can use to get started and not be too overwhelmed.

Why Vim?

Before I get started with the basics of Vim, why would you use it in the first place?

For me it boils down to this: I love staying on the keyboard. Vim may not make you faster (in fact initially you’ll be a lot slower) but it can fit your workflow better.

Another big differentiator of Vim is Command Mode. The notion here is that you spend more time wrangling text rather than creating it from scratch. That’s certainly true of my code.

It is important, however, that in the larger software ecosystem, typing is not the bottleneck. Don’t expect Vim to make you build the right software faster.

Vim enables a keyboard-optimized workflow that may make you faster. YMMV. If you’re fast with TextMate or Emacs or don’t want to spend the time to learn something new, then Vim may very well not be for you.

Lastly, Vim is ubiquitous. It’s on every platform and you can carry your configuration (or a very large set of it) everywhere. People frequently put their vim configurations on Github for themselves and others to utilize.

Getting MacVim

Almost all Unix-based systems (like Mac) include a terminal version of Vim. The version included on OS X isn’t compiled with Ruby support, so some plugins won’t work. In addition, it doesn’t have OS-level integration like Copy & Paste in the same buffer.

Most Vim users I know use MacVim, which comes pre-compiled with Ruby support, has tabs, and more.

If you have homebrew installed, just type:

1
brew install  macvim

If you’d rather grab a pre-built binary, then head on over here.

You’ll also want to make sure that the mvim binary is in your path.

Basic Vim Navigation

I won’t cover everything you can do in Vim here, but here’s just enough to get you started:

In Command Mode:

  • Press h, j, k, l to move the cursor around. It will feel weird, but you start to appreciate not lifting your hand off of the home row to reach for the arrow keys.
  • Press G to go to the end of a document, gg to go to the top of the document.
  • Press i to go to insert mode at the current position
  • Press I to insert at the beginning of the line
  • Press a to “append” content after the cursor
  • Press A to “append” content at the end of a line
  • Type cw (“change word”) to replace the current word and go into insert mode
  • Type dta to (“delete ‘til the letter a”) in a line

In Insert Mode:

  • Press esc to go back to command mode.

Commands:

  • In Command Mode, you can type commands by prefixing them with :.
  • To write the changes to the current buffer (save) type :w and hit enter. Often times you’ll write & quit in one command, with :wq.

Feel free to use the mouse & arrow-keys while you’re getting used to everything. It will feel weird.

For more Vim-fu, definitely check out this PeepCode screencast.

Installing a Base Set of Plugins with Janus

The real power of Vim is in the plugins, and fortunately Yehuda Katz & Carl Lerche have put together an opinionated and useful set of plugins that are pre-configured and work well together. Take a look at the plugins it includes here.

Getting Janus installed is easy. If you are super trust-worthy and don’t mind running a script blindly (I don’t recommend it) you can simply run:

1
curl https://raw.github.com/carlhuda/janus/master/bootstrap.sh -o - | sh

More explicit instructions for the paranoid can be found on the github page.

Once you have Janus installed, your Vim will be on steroids. Don’t worry though, I’ll try to cover the most important things you’ll be using.

Getting a Decent Theme installed

MacVim installs a hundred nasty looking themes, but a few of them are worth taking a look at. Here are some that I like:

  • molokai
  • railscasts
  • vividchalk
  • vibrantink

If you want to install other themes (like this nice github one) then you simply download it & copy the theme.vim (or whatever the theme is called) to ~/.vim/colors.

To switch between the themes that are installed, you can use the menu, or you can type :colorscheme <scheme>.

To set defaults for your installation, you’d normally add commands to ~/.vimrc however Janus has taken that file over. It instead reads your settings from ~/.vimrc.local. In order to provide settings for graphical Vim installations (like MacVim) there’s also a ~/.gvimrc file.

Open up that file (:edit ~/.gvimrc) and add the following commands:

1
2
colorscheme github
set guifont=Menlo:h14

Feel free to tweak this to contain your favorite color scheme & font. In order to see these changes you have to “source” the file:

1
:source %

(% here means “current file”)

You should see the changes take effect immediately.

Opening MacVim with a “Project”

One common thing in TextMate is to cd into a project and then type mate . which will open TextMate’s project drawer with all of the files in that directory loaded up.

In MacVim, you can do the same. Navigate to a folder with some content (like a Rails app) and type: mvim .

You should see something resembling a file navigator. You can navigate these with the same movement commands from above.

Once you’ve chosen a file, press enter to open it in the buffer.

Janus comes with NERDTree, which has similar behavior to TextMate’s Project Drawer. Open up the NERDTree pane by typing <leader>-n or \n. By default the leader key is set to backslash. The leader key is a special, configurable key used to create quick shortcut combinations.

The NERDTree window can be collapsed by typing <leader>-n again.

You might want to instead find the file by searching for it by name. For that, the aptly-named Command-T plugin can be hepful.

Command-T can be activated (by default) with <leader>-t. Start typing and it will auto complete the results.

Scared Yet?

Writing this reminds me of how hard it was to get started. I can only offer some encouragement that with practice, Vim does start to feel like you can leverage your fast typing skills to really.

Practice only a couple of commands at a time. Really learn what they are doing and then move one to the next command. Print out a cheet sheet. Pair with someone else who uses Vim.

I hope you found this intro useful. I’ll cover some more Vim tricks as time goes on.

A Fresh Start?

So I’ve been thinking of ditching the traditional blog for a while now. My current blog is powered by WordPress, which is powerful enough, however it always seems like a hassle to maintain. There are also no fantastic blog editors for the Mac (still).

This time I’m going in a completely new direction. This blog is powered by Octopress (which uses Jekyll as the engine. I’m not going to import old posts and I’m not going to worry about integrating a lot of features. Just epic content, that’s it!

Posts are composed in Markdown (I’m using vim to write this), static HTML is generated and the blog is then deployed to a git repository.

Will it make me blog more? I hope so, but only time will tell!