NR Time - Powerful time tracker for Mac OS X

Feel the ease of time tracking with NR Time. Log your time expenses in the billing-friendly format with minimal effort.

OCUnit: Two things they never say

Posted: August 6th, 2009 | Filed under: Programming | Tags: , | No Comments »

What if you followed all official (first, second, third) and unofficial tutorials to the letter, but still can’t make your tests run? Well, it’s what it was for me today. Here are two things I couldn’t find anywhere and had to figure myself:

  • If you see only one Unit Test Bundle build error, and it’s says “Failed tests for architecture ‘i386′ (GC OFF)” (slight variations depending on your platform and the state of the GC flag), you don’t have any tests in the bundle. Yes, go check that counter in the Compile Sources task of your test target.
  • If you added the application as the dependency to the test bundle, wrote the test that uses one of the classes and see the link error like below, you didn’t add any source files being tested to your test bundle for compilation. I know it’s insane to add them one by one, but it’s how they designed it. To make it a bit easier, right-click on the “Groups & Files” header, choose “Target Membership”, make sure your tests bundle is you current target and start checking missing sources.

    ".objc_class_name_XYZ", references from:
    literal-pointer@__OBJC@__cls_refs@XYZ in XYZTests.o
    sumbol(s) not found
    collect2: Ld returned 1 exit status


iPhone: Black navigation bar in “More…” view

Posted: August 6th, 2009 | Filed under: Programming, iPhone | Tags: , , | No Comments »

On iPhone, there’s the tab bar control that we, developers, can use to switch between several pages. It appears as a black stripe with icons at the bottom of the screen. Probably, the most famous is the tab bar of the Clock application:

Clock tab bar

It can show up to 5 icons and if there’s not enough space left, the last one is replaced with the “More …” item. When clicked, it shows the nice view with the list of all available options that didn’t fit into the tab bar. UITabBarController delegates the job to the UINavigationController. Now why I tell all this?

By default, the UINavigationController uses that standard blue top bar, but what if I want it to be Black as in the rest of my app?

First, let’s change the style of the “More …” page top bar. It’s all pretty straight forward as you can see. Just get the navigation controller and set the style of its bar:

tabBarController.moreNavigationController.navigationBar.barStyle = UIBarStyleBlack;

Finally, let’s change the style of the bar on the “More …” / Edit page (that says “Configure” by the way). It appears that you can’t drill down into the object model like above, but have to catch the moment when the editor is about to come out and do the magic. For this to happen, you needthe tab bar delegate (UITabBarControllerDelegate protocol) and use the tabBarController:willBeginCustomizingViewControllers: callback to nail it:

tabBarController.delegate = self;

and later:

- (void)tabBarController:(UITabBarController *)tabBarController
        willBeginCustomizingViewControllers:(NSArray *)viewControllers {
    UIView *views = [tabBarController.view.subviews objectAtIndex:1];
    UINavigationBar *navBar = [[views subviews] objectAtIndex:0];
    navBar.barStyle = UIBarStyleBlack;
}

In the above 3-liner, you can see that we do the trick to actually find the navigation bar. It works nicely on iPhone 3.0, but may change in the future, so be careful.

Don’t forget that you can always subclass UITabBarController and hide all this customization logic inside to stay on the clean design side. In my work, I do that and used the tabBarController here to clearly state what model we operate on.

That’s all, folks. Hope it helped someone to save a couple of hours.


iPhone: Background Lookup and Dictionaries

Posted: June 1st, 2009 | Filed under: iPhone | Tags: , , , , , | 1 Comment »

First of all, for those who don’t follow me on twitter (@spyromus), this year I’m working on my Cocoa / Cocoa Touch skills. Love it immensely so far and especially how things are nicely done in the iPhone department. A sheer pleasure.

During the last few weeks I tried several iPhone dictionaries and surprisingly all of them ( I mean ALL ) are coded in a strange way. The one of the most important parts — word entry — is implemented in a totally unimaginative straightforward way where it either looks up whatever you enter against their huge databases after every new letter or does that periodically. Both versions block the search box every now and then and don’t let you enter your searches quickly.

No finger pointing here certainly, but you guys know who you are. I tried to contact authors and share this bit of knowledge, but it’s either http://localhost/ as the support link or no link at all, so… the least I can do is to share it here. Hope it’ll be of some help.

Here’s the part of a XYZViewController:

- (void)viewDidLoad {
  operationQueue = [NSOperationQueue new];
  [super viewDidLoad];
}

- (void)searchBar:(UISearchBar *)searchBar
    textDidChange:(NSString *)searchText {
  [operationQueue cancelAllOperations];

  SearchOperation *op = [[SearchOperation alloc]
    initWithText:searchText dictionary:dictionary controller:self];

  [operationQueue addOperation:op];
  [op release];
}

Where SearchOperation is a subclass of NSOperation and its main method looks something like this:

- (void) main {
  [NSThread sleepForTimeInterval: 0.25f];
   
  if (![self isCancelled]) {
    // Do your searching magic here ...
    [controller performSelectorOnMainThread:@selector(searchResult:)
      withObject:...
      waitUntilDone:NO];
  }
}

The idea is that when the user types a letter, the searchBar:textDidChange: is called, but it doesn’t do the search right away. Instead it creates an instance of the SearchOperation which represents a lengthy dictionary lookup and queues it. Each SearchOperation sleeps 1/4 seconds before it starts doing any work. In fact, before the actual start it checks if it was canceled and does that periodically during the search.

So when it can be canceled? That’s why we have the cancelAllOperations call in the queuing code. If the user types, every next letter results in the cancellation of previous search operations and none of them will complete or even start. Moreover, the user interface will never be blocked and your users can type away freely and only if they stop, the GUI will follow and show the results.

You see? Simple.