OSX: Renaming Fonts (For Free!)

I just got a huge problem. I’m working on an iOS app, and it turns out that we need to maintain compatibility with iOS 4. So… the problem is that we use custom fonts. A lot of them. That shouldn’t be an issue. BUT… i got to notice that iOS 4 supports up to two different fonts per family.

Long short story, if you’ve got a font family with… 5 different fonts, iOS 4 will load just two of  them. So how do we solve it?.

Simple!. We rename some of the extra fonts. Thing is, there are lots of tools to do that. But they’re paid. And… dude, it’s just renaming a font!. That’s where TTX comes in.

TTX is an opensource tool that basically converts a font into a readable XML. So… you just need to parse your OTF file, change the font name… and run TTX again, to pack it up into an OTF file, back again.

So far so good. But i was getting an error while trying to run TTX on OSX 10.7.3. The problem is that TTX works fine only in 32 bits mode.

So…. if you’re also having problems, just run this command, and you’re good to go:

[cc lang=”bash”]
defaults write com.apple.versioner.python Prefer-32-Bit -bool yes
[/cc]

NSMutableSet: Filtering Duplicate Elements

Suppose that your app has X amount cached objects. And suppose that there is a slight chance that.. since the backend doesn´t actually know what it is exactly that you have cached (and what you don´t have cached), it might send duplicates.

So… what do we do?. Shall we write a for routine checking dupes?. No way. There is a far more performant way to achieve this, and it requires less lines of code.

Steps…

  • Implement your own ‘isEquals’ and ‘hash’ methods, in your model object. For instance…

[cc lang=”objc”]
– (BOOL)isEqual:(id)object
{
    SomeClass* secondObject = (SomeClass*)object;
    return ([secondObject isKindOfClass:[self class]] && 
            [[secondObject id] isEqual:[self id]]);
}

– (NSUInteger)hash 
{
   return [_id hash];
}
[/cc]

  • Simply instantiate a NSMutableSet and add the cached objects plus the objects retrieved from the backend. If the set already has an object for any given ID, and you attempt to insert a new one… but with the same id, it´ll just not work.

So… no more filtering things by hand. NextSTEP’s code will do the trick, from now on!

Grand Central Dispatch: Perform Block After Delay

We have seen in a previous post the proper way to write a singleton, with the help of our good friend Grand Central Dispatch.

In this opportunity, i´d like to share a goodie i´ve learnt few days ago. I suppose many of you had problems with the following scenario. You have to perform a task, which is time consuming, and you need to place, onscreen, an Activity Indicator.

Although the Activity Indicator performs the animation on its own thread, you need to “spare some time” in the main thread for it to begin working. I mean… you can execute [indicator startAnimating] right away. But… if you don´t release the main thread, even for a short moment, surprise!. The spinner won´t work.

So… the common solution is to split that method into two parts, and execute ‘performSelector: withObject: afterDelay:’. That´s where GCD comes in.
We can do the exact same thing… but with blocks!!. That´s SO MUCH COOL…!

[cc lang=”objc”]
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,
0.1f * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
     // …  Your code
});
[/cc]

Note: The delay, in this example, is of about 0.1 seconds.

UITableView: Make room for a new cell, and insert it!

Suppose you wanna insert a new row at the bottom of a table. The first thing you need to do is to calculate the content offset. Suppose you already know the height of the new cell, and it’s stored into the variable ‘newCellsHeight’. Then…

[cc lang=”objc”]
CGPoint contentOffset = CGPointZero;

contentOffset.y = _tableView.contentSize.height
+ newCellsHeight
– _tableView.frame.size.height
+ _tableView.contentInset.bottom;

Once you’ve calculated the contentOffset (considering the current contentInsets)… you should make sure it’s a non-negative value, to prevent quirks:

// Do we need to scroll down?
if(contentOffset.y > 0.0f)
{
[_tableView setContentOffset:contentOffset animated:YES];
}
[/cc]

The last step would be to actually insert the rows. Please, consider that a delay should be applied, so the insert rows animations won’t break the scroll animation!

Xcode: Number of lines

I’ve been unable to figure out how to do this, actually, within Xcode. But this can also be accomplished by means of this short script:

[cc lang=”bash”]find . “(” -name “*.m” -or -name “*.mm” -or -name “*.cpp” “)” -print | xargs wc -l[/cc]