Posted on by Joel Kin | Leave a comment

Quick Tip: Drawing Right Side Up With Core Text

Anyone who has decided to explore using Core Text on iOS has probably noticed that everything is drawn upside down. This is because Core Graphics contexts that have been created with functions provided by UIKit (such as UIGraphicsBeginImageContext, or the drawRect method in a UIView) have a coordinate system with it’s origin (0,0) located in the top left corner. However, in the days before iOS, and when using a more traditional approach to creating a CGContext (CGBitmapContextCreate for example), the origin starts in the lower left corner. Because of its desktop origins and close ties to Core Graphics, Core Text expects the more traditional coordinate system; Without context adjustments, text is drawn as if it were mirrored vertically.

When I first started dabbling with Core Text, CGContextSetTextMatrix seemed like a reasonable place to start in order to fix this – it accepts a CGContextRef and a CGAffineTransform, and something like the following will indeed flip your text.

CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));

Great, problem solved! Except that it’s not, especially if you plan on having more than one line of text using something like CTFrameDraw. In this case, just transforming the text matrix will flip your letters, but doesn’t adjust the direction in which the frame lays out line breaks. What you’ll notice is readable text, but with last line starting at the top.

Basically, you can think of the transform applied with CGContextSetTextMatrix as being applied to each individual letter as it is drawn. If you want to impact that way a segment of text is laid out as a group, then a transform needs to be applied to entire context. The following will both flip your letters, and lay text in the proper direction

CGContextTranslateCTM(context, 0.0f, contextHeight);
CGContextScaleCTM(context, 1.0f, -1.0f);

Mind you, transforming individual letters can still be fun! In the last view of the screenshot we’ve applied the following set of transforms to rotate each letter by 45 degrees, while maintaining proper layout and line breaks.

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeRotation(45 * M_PI / 180.0f);
CGContextSetTextMatrix(context, transform);
CGContextTranslateCTM(context, 0.0f, rect.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);

Posted in Code | Tagged , , | 3 Comments

Localizing Arbitrary Strings the Scripty Way

I bet you saw my post about localizing US states and said to yourself, “Ha! That little sed script won’t do much for arbitrary strings!” You’re a jerk, but yes, you’re right. Before I give it away, does anyone see the problem with the previous script?

sed 's/@"[^"]*"/NSLocalizedString(&, nil)/g'

Let’s try it on some completely pseudorandom strings that I am about to pseudo-make up.

@"hey man"
NSLocalizedString(@"hey man", nil)
@"what's up"
NSLocalizedString(@"what's up", nil)
@"what\"s up"
NSLocalizedString(@"what\", nil)s up"

Uh oh. Clearly this simple script does not take escaped quotes into account. This is kind of a complex problem! We can’t just match strings of the type \", because there may be escaped backslashes in front of a real quote (ie \\"). So we have to match quotes preceded by an odd number of backslashes. And there could be any number of instances of that pattern, anywhere in the input, so we have to interleave it with the “every other character” match. Lucky for you I already did the work!

sed -E 's/@"([^"\\]*((\\\\)*(\\")*)*)*"/NSLocalizedString(&, nil)/g'

What the hell is this mess? First things first.

  • sed -E: the -E flag tells sed to use extended regexp, which allows for strings (in parentheses), not just individual characters.
  • @": match the beginning of an NSString.
  • [^"\\]*: match any number (*) of characters that are neither a double quote nor a backslash (this is confusing because we have to escape the backslash to keep sed from interpreting it).
  • (\\\\)*: match any number of paired backslashes, ie, backslashes escaped in the input.
  • (\\")*: match any number of double quotes immediately preceded by a backslash (escaped for sed, non-escaped in the input); that is, any number of escaped double quotes.
  • " match the closing double quote.

Now we can put some of these elements together to construct a more complex regular expression.

  • ((\\\\)*(\\")*)*: match any number of strings of the pattern “any number of escaped backslashes, followed by any number of escaped quotes”.
  • ([^"\\]*((\\\\)*(\\")*)*)*: and finally, match any number of strings of the pattern “any number of non-quote, non-backslash characters, followed by any number of double quotes preceded by odd numbers of backslashes”.

It’s critically important to remember that “any number” includes zero. That’s why this pattern can match the implied most complex pattern of input — something like @"a\\\"b\\\"c\\\"" — but still perform fine on input like @"hey man". Things that don’t occur in the input still occur zero times — just enough to match.

Okay, whatever! What’s the output look like?

$sed -E 's/@"([^"\\]*((\\\\)*(\\")*)*)*"/NSLocalizedString(&, nil)/g'
@"hey man"
NSLocalizedString(@"hey man", nil)
@"what\"s up"
NSLocalizedString(@"what\"s up", nil)
@"what\\\"s up"
NSLocalizedString(@"what\\\"s up", nil)
@"a\\\"b\\\"c\\\""
NSLocalizedString(@"a\\\"b\\\"c\\\"", nil)
@"\\\\\"
@"\\\\\"

Great! The pattern performs as expected on simple input, and on complex input catches the escaped quotes. It even fails on the last input, an invalid string which is never closed. Now we can localize not only input we know is free of exceptional conditions, but any arbitrary strings we might come across, all with the help of our two friends sed and regexp.

Posted in Code | Tagged , , | Leave a comment

Mistakes Were Made: Initialize Your Locals

“Mistakes Were Made” may or may not end up being a post series where we talk about actual things we have done wrong, and the lessons thereby learned.  The uncertainty is about whether revealing all this stuff will make us look unemployable.  We’re not, I promise.

One of the pleasant little details that make working in Objective-C such a joy is that instance variables are automatically zeroed out at creation.  That means that when you define a pointer in your object’s interface, you don’t have to explicitly set it to NULL in the init method — the compiler will take care of that for you, freeing your mental capacity for bigger and better things.  Languages with more strictly managed memory, like Java, will also do this, but looser languages like C and C++ will not.

Great, so what?

Problem is, you might get used to this and expect local variables to come zeroed out too.  They don’t.  I knew this, but was reminded of it the hard way recently.  A certain nameless application on the App Store has a table view that contains another table view in one cell.  The height for this outer cell is calculated thusly:

- (float)preferredHeight
{
	float height;
	int i;
	for (i = 0; i < numCells; i++)
    {
		height += cellHeights[i];
    }
    return height;
}

Whoops.  Anyone see the problem?  That’s right, height is used uninitialized — any old junk values that happened to be in there are added to the final count.  This is a particularly pernicious problem because on debug builds, the memory happened to be set up such that the initial value for height was somewhere around 9.71498046e-30 — for all practical purposes, zero.  Even on a release build tested locally, it was 14, easy enough not to notice.  It wasn’t until the app made it out into the wide world that I started to see real issues, but now, many people using that nameless application are seeing a cell that’s way taller than it should be.

What do I do?

There’s a warning for that!  Add -Wuninitialized to your build flags, or if you’re using Xcode, turn on the warning for “Uninitialized Automatic Variables” under Build Settings.  For some reason this is NOT the default for new Xcode projects!  I guess Apple expects us all to be smarter than I am.  There’s also -Wmaybe-uninitialized, which is more aggressive about warning when the variable may or may not have a value set, like cases in a switch statement that you know are impossible but the compiler doesn’t.  (Switch statements should always have a default!)

Of course, you should always initialize your variables anyway.  The warning should serve as a safety net, but clearly you can’t depend on it.  Given this, it might make sense to zero out your instance variables in your init methods, for consistency’s sake: it’s easier to do the wrong thing if sometimes it’s the right thing.  I know I would rather do too much zeroing than too little.

Posted in Code | Tagged , , | Leave a comment

CALayers v. CGLayers, or, Which Layer, Player?

What’s the Deal?

An evergreen source of confusion for developers new to graphics on iOS is the existence of multiple Apple-provided graphics frameworks, and multiple “layer” objects within those frameworks.  We’re told to use Core Animation for compositing and animation, and Core Graphics for two-dimensional bitmap drawing (as well as rarer things like low-level text layout and PDF rendering).  Core Animation’s basic class is the CALayer, and Core Graphics has its own CGLayer object.  Surely they are analogous!  Might we construct an SAT-style comparison?

CALayer : CA :: CGLayer : CG?

Despite one’s intuition, not even close.  This is just an unfortunate naming scheme that has wasted countless developer hours and spawned innumerable forum threads.  Let’s take a look at the differences.

CALayer

Yup, this one you’ll want to know about.  CALayer is one of the most important classes on iOS, right up there with UITableView.  The entire windowing system on iOS runs on top of Core Animation; this means that every single thing you see on screen lives in a CALayer.  They can be positioned, transformed in three(ish*) dimensional space, and a bunch of other neat stuff.  Perhaps most importantly, they can be filled with arbitrary bitmap content – and this is where the confusion sets in.  That bitmap content is often provided by Core Graphics!  When putting Core Graphics content into a CALayer, surely a CGLayer is the right way to go?

No.

Haven’t you been listening?

CGLayer

CGLayers are super cool drawing optimization objects – on the desktop.  Their main use is to cache drawing stuff – either bits or, for instance, PDF drawing commands – for re-use.  They make things like drawing a sprite for a game much faster, for a few reasons.  First, their contents can be stored on the graphics card, meaning that drawing them to the screen is super fast as compared to a bitmap stored in memory.  Second, they are constructed with a specific drawing context in mind, so they can optimize their contents for the format of that context.  And third, since drawing them into a context is so much faster than drawing an arbitrary bitmap, they can enable high-speed animation the Core Graphics way (re-rendering the screen each frame).

Thing is, these advantages don’t carry over to iOS.  When you set a CALayer’s contents, or draw into it, that bitmap is always stored on the graphics card.  That’s just the nature of Core Animation, as a framework built on top of OpenGL.  And practically speaking, there is really only one format you’ll be drawing into – that’s the nature of a closed ecosystem of devices with one optimal pixel format.  (If your app constructs PDFs on the device, this is not the blog post for you.)  As far as animation goes, well, it’s called Core Animation for a reason.  What it comes down to is that in iOS, using a CGLayer buys you nothing but additional complexity.

TL;DR

Don’t use CGLayers on iOS.

* a subject for another post!

Posted in Explanation | Tagged , , , | 2 Comments

(More) Descriptive Logging

Update 9/30/11: This blog post isn’t quite complete. Have a look at Description Isn’t Enough, and remember to use debugDescription as well.

Joel and I have been discussing the kinds of content we’d like to work on putting in our quaint little corner of the internet, and I feel like, along with other content, it will be quite useful if we make an effort to include beginner level tips.

Everyone wants a log*

I first got started with Objective-C and Cocoa when my first generation iPhone was still running 1.x.x. The jail breakers had made the toolkits easy to use, and running home brew applications on the device was finally a reality. Unfortunately, this reality had one major pit fall – there was no tethered development, which meant there was no debugger. My debugging existence was made up entirely of log statements, and NSLog() had become my right hand man.

And this is where the good stuff starts:

NSObject, the class that sits under every Obj-C object you will ever create, has a method named description that returns a string. This is the string you will see if you use GDB to print the object, or reference the object using the %@ specifier in a formatted string.

From the documentation for NSObject

+ (NSString *)description

A string that represents the contents of the receiving class.

Discussion

The debugger’s print-object command invokes this method to produce a textual description of an object.

NSObject’s implementation of this method simply prints the name of the class.

 

Common ways this method comes into play.

(gdb)po myObject
<MYObjectClass: 0x683c320>

NSLog(@"%@", myObject);
2011-07-26 08:50:43.975 MyApplication[19148:ef03] <MYObjectClass: 0x6a97ea0>

NSString *myDescription = [NSString stringWithFormat:@"%@", myObject];

Make It Yours

At this point, I’m sure everyone either knows where I’m going with this, or has already quit reading and set off to make their debugging logs more awesome. For those of you still with me, here’s the magic moment: You can make the log messages say whatever you want by simply overriding description in your classes! Amazing, isn’t it?

A lot of times, logged objects are pretty boring – you get a class name and a memory address *yawn*. But if you’ve ever logged an NSArray or UIView, it’s easy to see how things could be made much more interesting. For example:

<UIView: 0x6a991a0; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x6a992c0>>

Classes, pointers, frames, autoresizing masks – oh my! Imagine you had a class with a few properties that were essential bits of information for debugging, rather than creating complex NSLog statements or multiple gdb commands, you could wrap them all up in a nice and pretty description.

+ (NSString *)description
{
  // Abreviating variables like this is awful, don't do it!
  // This is merely and effort to fit everything in 
  // this stupid narrow window.
  NSString *format = @"<%@: %p; A = %@; B = %i>";
  NSString *cStr = NSStringFromClass([self class]);
  id a = self.A;
  int b = self.B;
  return [NSString stringWithFormat:format, cStr, self, a, b];
}

Voila – just like that, and you’ve got yourself with one hell of an informative log message.

note: If you aren’t yet comfortable with the various output options for formatted strings, I highly recommend bookmarking the String Format Specifiers

Console Spam

Now that you’ve got this fancy new tool for logging gobs of data to the console, TRY NOT TO BE A LOG SPAMMER! Be succinct in your object descriptions – a flood of data is no better than a dearth of it. Unless of course, your goal is to annoy coworkers, in which case I suggest using the following: Capital letters, symbols (the wider the better – @ is a good choice), and as many newlines as you can manage.

*It’s inappropriate to make references to the Ren & Stimpy “Log” song without a link, so here it is

Posted in Code | Tagged , , | 2 Comments

Natural Scrolling is Natural

For the first 24 hours using Lion, I was beyond frustrated with the fact that scrolling was now “backwards”. Every time I’d move my mouse to a window and scroll, I’d have a jarring moment where my brain would cringe in confusion. I like to relate the feeling to the one I get when driving a car, and don’t quite depress the clutch far enough before shifting gears. Suddenly, an otherwise automatic combination of muscle memory is interrupted by a jarring lack of functionality

Having trouble efficiently getting even the simplest of tasks done, I set off to figure out how I could convince my brain that this new behavior wasn’t just WRONG. The world of twitter seemed to be on the fence. Ranging from folks calling “natural scrolling” an abomination that only makes sense for touch interfaces, to the apple evangelist types suggesting that Apple knows best, and to just “give it time”.

The Revelation

I have come to the following conclusion: This make sense for scroll wheels and trackpads alike, and there is one single mindset shift that is required for the new scrolling to make complete sense and it is, admittedly, a tough one to make.

Pre Lion,  scrolling with a wheel or gesture, was interacting with the scroll bars.
Post Lion, scrolling with a wheel or gesture, is interacting with the content.

(This is  why it’s pretty easy to come to the conclusion that this kind of scrolling [only] makes sense on a touch device. In very concrete terms – on a touch device, the thing you are directly in contact with is almost always the thing you are manipulating.)

Scrolling has always been contrived

That’s right, I said it – scrolling with a mouse wheel has always been an artificial concept. The first response I got to that statement was: “the same can be said of anything on a computer, it’s all a metaphor.” While this is obviously true, I don’t think many would disagree that some metaphors are more tightly coupled to their real world counterparts than others. The mouse and the cursor, for example, are inextricably linked. For all intents and purposes, the cursor is the mouse – or at least the virtual representation of it. Clicking, Right Clicking, Double Clicking, Clicking and dragging; all of them always result in some action being applied to the thing under the tip of the cursor.

At least this was true until 1996 when Microsoft came along with the IntelliMouse, with it’s fancy new convenience: the scroll wheel; and with that, the metaphor was suddenly broken. I loved the scroll wheel as much as the next guy, but the truth is, for the first time, doing something with the mouse wasn’t necessarily applied to the thing under the cursor. Sure, the scroll wheel almost always scrolled the content of the window immediately beneath the cursor, but it’s effect was the equivalent of clicking on a scroll bar (one potentially far off on the other side of the screen) and moving it around. Contrived as it may have been, I remember this new manner of interacting with a window to be pretty damn convenient, so who was I to argue!?*

For years, we all just learned and accepted that scrolling the wheel down meant we wanted to move the scroll bar down, and vice versa. As the laptop world adopted trackpads, and multitouch became a reality, it didn’t take a genius to see the value in adopting gestures that would allow a user to mimic the various input types available on a mouse. Continuing with the broken metaphor, we all adopted the “two finger scroll” gesture.

Touch Interfaces are Hard

Having been developing iOS applications since long before ‘iOS’ was even a thing, I’ve come to learn that the hardest parts of touch driven interface are driven by two key points: Fingers are fatter than cursors, and breaking the rules of physics tends to confuse the hell out of people. These two facts make one part of a touch interface significantly harder to create than others – care to guess which it is?

Scroll Views.

Given that Apple’s foray into touch interfaces started with the iPhone, I feel like it’s worth pointing out another truism: Touch interfaces are hard, and touch interfaces on tiny little screens is harder. The lack of screen real estate on an iPhone means it’s necessary to consider UI elements the way one might consider weight in a sinking boat – if it’s not needed, throw it out. With how large the scroll bar would need to be to accurately interact with it, it’s not much of a shock that Apple designers figured out a way to cut out this screen gobbling UI element in lieu of a more intuitive way to scroll. To support this shift, Apple turned the scroll bar into a scroll “indicator” that gets out of the way when it’s no longer of use.

Full Circle

Few will argue that there is a fair amount of iOS-ification going on in Lion – and this new scrolling is the most in-your-face example of them all. With the iPhone, Apple has clearly learned real life lessons about the importance of “maintaining the metaphor” within an interface. And using the platform’s success, it’s not difficult to make the case things should be done the same as they’ve always been done.

It’s no coincidence that the new scroll bars in Lion are smaller, subdued, and out of the way – just like they are in iOS. Consider the cursor as a finger, and this new scrolling really doesn’t seem so crazy after all. Remember that you are moving the content – the big thing taking up all the space – and not that obscure little thing over on the side, and I’m confident scrolling (eventually) will indeed feel natural.

* In 1996 I was 14 and I’m pretty sure I was still using AOL, my parents were just about the only people I was arguing with.

Posted in Philosophy | Tagged , , , | Leave a comment

Localizing your US States array

Suppose you have a whiny co-worker who insists that all user-facing strings be localized. That’s what scripting tools are for, right? Specifically sed, in this case.

sed 's/@"[^"]*"/NSLocalizedString(&, nil)/g'

This little script will match NSStrings and replace them with a naive NSLocalizedString call. If you’re unfamiliar with sed (or even if you’re not), it matches regular expressions in an input and performs operations on them, usually substitution. In this case s is for “substitute”, @[^"]*" is the expression to match (if you’re unfamiliar with regular expressions, [^"]* means “any number of characters that are not a double quote”), and the NSLocalizedString bit is the replacement, with & meaning the previously matched string. g means apply it globally, ie, more than once. Let’s see what happens when we use it on our states array from the previous post:

$ echo '[NSArray arrayWithObjects:@"Alabama", @"Alaska", …, nil]' | sed 's/@"[^"]*"/NSLocalizedString(&, nil)/g'

[NSArray arrayWithObjects:NSLocalizedString(@"Alabama", nil), NSLocalizedString(@"Alaska", nil), NSLocalizedString(@"Arizona", nil), NSLocalizedString(@"Arkansas", nil), NSLocalizedString(@"California", nil), NSLocalizedString(@"Colorado", nil), NSLocalizedString(@"Connecticut", nil), NSLocalizedString(@"Delaware", nil), NSLocalizedString(@"Florida", nil), NSLocalizedString(@"Georgia", nil), NSLocalizedString(@"Hawaii", nil), NSLocalizedString(@"Idaho", nil), NSLocalizedString(@"Illinois", nil), NSLocalizedString(@"Indiana", nil), NSLocalizedString(@"Iowa", nil), NSLocalizedString(@"Kansas", nil), NSLocalizedString(@"Kentucky", nil), NSLocalizedString(@"Louisiana", nil), NSLocalizedString(@"Maine", nil), NSLocalizedString(@"Maryland", nil), NSLocalizedString(@"Massachusetts", nil), NSLocalizedString(@"Michigan", nil), NSLocalizedString(@"Minnesota", nil), NSLocalizedString(@"Mississippi", nil), NSLocalizedString(@"Missouri", nil), NSLocalizedString(@"Montana", nil), NSLocalizedString(@"Nebraska", nil), NSLocalizedString(@"Nevada", nil), NSLocalizedString(@"New Hampshire", nil), NSLocalizedString(@"New Jersey", nil), NSLocalizedString(@"New Mexico", nil), NSLocalizedString(@"New York", nil), NSLocalizedString(@"North Carolina", nil), NSLocalizedString(@"North Dakota", nil), NSLocalizedString(@"Ohio", nil), NSLocalizedString(@"Oklahoma", nil), NSLocalizedString(@"Oregon", nil), NSLocalizedString(@"Pennsylvania", nil), NSLocalizedString(@"Rhode Island", nil), NSLocalizedString(@"South Carolina", nil), NSLocalizedString(@"South Dakota", nil), NSLocalizedString(@"Tennessee", nil), NSLocalizedString(@"Texas", nil), NSLocalizedString(@"Utah", nil), NSLocalizedString(@"Vermont", nil), NSLocalizedString(@"Virginia", nil), NSLocalizedString(@"Washington", nil), NSLocalizedString(@"West Virginia", nil), NSLocalizedString(@"Wisconsin", nil), NSLocalizedString(@"Wyoming", nil), nil]

Like magic! Now you can tell your coworker to suck it, sed solved all your problems. As it tends to do.

Posted in Code | Tagged , , , , | Leave a comment

US States in an NSArray

Save yourself a little typing time, take advantage of mine.

[NSArray arrayWithObjects:@"Alabama", @"Alaska", @"Arizona", @"Arkansas", @"California", @"Colorado", @"Connecticut", @"Delaware", @"Florida", @"Georgia", @"Hawaii", @"Idaho", @"Illinois", @"Indiana", @"Iowa", @"Kansas", @"Kentucky", @"Louisiana", @"Maine", @"Maryland", @"Massachusetts", @"Michigan", @"Minnesota", @"Mississippi", @"Missouri", @"Montana", @"Nebraska", @"Nevada", @"New Hampshire", @"New Jersey", @"New Mexico", @"New York", @"North Carolina", @"North Dakota", @"Ohio", @"Oklahoma", @"Oregon", @"Pennsylvania", @"Rhode Island", @"South Carolina", @"South Dakota", @"Tennessee", @"Texas", @"Utah", @"Vermont", @"Virginia", @"Washington", @"West Virginia", @"Wisconsin", @"Wyoming", nil]

 

Posted in Code | Tagged , , | 15 Comments