Wednesday, July 06, 2011

Easier Screen Shots In OS X: Make the keyboard shortcuts F5 & F6

I don't know why I didn't think of this sooner.

It's kind of an open secret that taking screenshots by default in OS X Snow Leopard and now OS X Lion is not as obvious as it should be. All iOS devices have an easier screenshot gesture (tap the home + lock button for a second) than OS X does. Take a look at the screenshot below:

OS X Lion Default Screen Shots Keyboard Shortcuts

3 or 4 keys to trigger a screenshot! It's always been a tricky combination to remember for experienced OS X users, and when you tell Windows converts that their precious Print Screen key has been replaced by 3 & 4 button combos, they almost always say how is this easier

The answer of course is that it's not and never has been. It's more powerful, in OS X you get to draw a box around the part of the screen you want, but it's a hard sell. I usually just tell somehow to launch Grab.

After I installed the OS X Lion GM tonight, I was looking through System Preferences to see what had changed, and I was disappointed to see the default keyboard shortcuts for screen shots hadn't changed. So I started wondering what keys I could map screenshots to, and then it hit me:

Apple Bluetooth Keyboard

F5 and F6 are unmapped to critical operating system functionally, they're blank guys on my Apple Wireless Keyboad!!!

I couldn't believe I hadn't thought of this before, or that Apple hadn't already done it. Maybe they just don't think taking screenshots is a common user activity in OS X, but it seems like everybody needs to take screenshots at some point, why not make it easy? So I changed my keyboard shortcuts to this:

OS X Lion New Screen Shots Keyboard Shortcuts

One caveat, F5 was already mapped to VoiceOver, so I put that on ⌥⌘F5 since I never use it.

I'll file a bug with Apple to propose getting these made the default keyboard shortcuts for screenshots, and put some kind of icon on the actual keyboard keys.

Tuesday, July 05, 2011

The Reason Why an Objective-C Protocol Doesn't Implement respondsToSelector:

I've been having a lot of fun with Objective-C protocols lately. In one of the projects I'm on, I've been working to eliminate warnings from the compiler. One of those warnings is that respondsToSelector: isn't found in your delegate or data source. When working with a delegate or data source, two different naming conventions for Objective-C protocols, a typical pattern your code follows is to see if your delegate or data source actually implements a method defined in your protocol, like this:
- (void)notifyDelegateOfButtonTap
    if (self.delegate &&
       [self.delegate respondsToSelector:@selector(protocolSampleViewController:didTapButton:)])
        [self.delegate protocolSampleViewController:self didTapButton:self.button];
The protocol definition would typically look like this when implementing this pattern:
@protocol ProtocolSampleViewControllerDelegate
- (void)protocolSampleViewController:(ProtocolSampleViewController *)protocolSampleViewController didTapButton:(UIButton *)button;
This is a typical protocol definition as code completed in Xcode 3.x, with the addition of @optional just to maintain pattern correctness for the example. In Xcode 4.x, the code completed @protocol definition template looks like this:
@protocol protocol name <NSObject>
As you might have guessed by now, the <NSObject> added behind the protocol name is the key. That's because it's actually the NSObject protocol that defines most of the core methods that the NSObject class implements, including respondsToSelector:

Once you make sure all your protocol definitions adopt the <NSObject> protocol, then calling respondsToSelector: on your delegate or datasource variables won't result in compiler warnings.

One more could cast your delegate or data source variable to id like this:
[(id)self.delegate respondsToSelector:@selector(protocolSampleViewController:didTapButton:)]
That is an ugly solution and doesn't help you understand another key feature of protocols, inheritance, which I plan to cover in an upcoming post.