Vincent Gable’s Blog

August 15, 2010

My UIViewController Template

Filed under: iPhone,Objective-C,Programming,Sample Code | , , ,
― Vincent Gable on August 15, 2010

I haven’t formalized this as a proper Xcode template, but this is what’s in my PrototypeViewController.m file that I copy/paste over the UIViewController subclasses Xcode makes.


@interface MyViewController ()
@end

@implementation MyViewController
- (void) releaseViewObjects;
{
	if([[self superclass] instancesRespondToSelector:@selector(releaseViewObjects)])
		[(id)super releaseViewObjects];
}

- (void)viewDidUnload;
{
    [super viewDidUnload];
    [self releaseViewObjects];
}

- (void)dealloc;
{
    [self releaseViewObjects];
    [super dealloc];
}

@end

Here are the reasons why, in no particular order:

Commented-Out Code is Evil

Littering source code with “comments” full of crufty, obsolete, or unimplemented code is not a good thing. Xcode’s default template is full of commented-out code. If you’re totally new to the platform, starting from the templates aren’t a bad way to learn. But in my experiance, they do harm to a production code-base, by injecting hundreds of lines of commented-out code into a project.

Share code between viewDidUnload and dealloc With releaseViewObjects

In my world, releaseViewObjects is solely responsible for cleaning up every IBOutlet, and any objects created in viewDidLoad.

There are technical reasons why this is a little scary. Calling a method in dealloc is potentially risky, because the object may be in an invalid half-torn-down state, and because Dark Runtime Magicks could be afoot (see Using Accessors in Init and Dealloc.)

But in my experience, such bugs, although as scary as they sound, are rare corner-cases and still quite fixable. But every UIViewController needs to clean up after itself, so simplifying the universally common case is a net win.

The if([[self superclass] instancesRespondToSelector:@selector(releaseViewObjects)]) test wouldn’t be necessary if I added another class between UIViewController and my real code, so that I was sure my class’ super implemented releaseViewObjects. But adding a subclass just to implement one empty method, to avoid a two-line test, isn’t worth it.

The (id)super cast is intentional, to prevent compiler warnings.

I have to use the more complex [[self superclass] instancesRespondToSelector: test, because -[super respondsToSelector:] doesn’t work.

I Won’t Really Get To didReceiveMemoryWarning

I’m not proud to admit this, but it’s true. We’ve all been told that a good iPhone program must release resources when it gets a memory warning, or else it will be killed. But in practice, there have always been better places to spend my time (or at least it sure feels that way!) Spending a few hours in Instruments to fix leaks prevents memory warnings in the first place, and that’s a bigger win.

Besides, 80% of what didReceiveMemoryWarning would do is handled in releaseViewObjects, which is automatically called by the default implementation.

So I break with Xcode and leave didReceiveMemoryWarning out of my template, because the default class won’t use it.

What About init?

I don’t have a default init(With…) method. I try to use autorelease-ed objects everywhere I can, so I’m more comfortable implementing +[MyViewController viewControllerForFoo:].

But I don’t have a default constructor of any kind, because a constructor should take every value it needs, and I don’t know what these values are until I’ve written a bit more of the class. It’s a chicken and egg problem.

Once I’ve written out a bit more of the class, I’ll usually build something that looks like:

+ (RouteMapViewController*) routeMapViewControllerWithWaypoints:(NSArray*)waypoints mapRegion:(MKCoordinateRegion)region;
{
	RouteMapViewController *vc = [[[self class] new] autorelease];
	vc.title = NSLocalizedString(@"The Path",@"");
	vc.hidesBottomBarWhenPushed = YES;
	vc.waypoints = waypoints;
	vc.mapRegion = region;
	return vc;
}

For what it’s worth I use this pattern to implement a 0-argument -init.

Empty Class Extension

Class extensions are the best way to have “private” things in Objective-C. They let the compiler catch objects using another object’s private methods. They let a class have publicly readonly, but internally readwrite, properties.

Bottom line: every nontrivial object I’ve written uses them, so they’re in my template.

Nothing Else (For Now)

My template is smaller than Xcode’s. That is by design. Outside of esoteric contests, having less code to maintain is a good thing. So I prefer a template that tries very hard to avoid adding code I don’t need.

Do you disagree with any of my choices? Please leave a comment explaining why.

December 9, 2009

Compile Safer

Filed under: Bug Bite,C++,Cocoa,iPhone,MacOSX,Objective-C,Programming | , , ,
― Vincent Gable on December 9, 2009

Peter Hosey explains what warnings he uses and why. It’s good, but long. Fortunately, you can just grab a script, and enable those warnings in your Xcode projects.

Warnings = Errors

If I could force just one compiler flag on everyone who’s code I use, it would be TREAT_WARNINGS_AS_ERRORS. As a rule, things don’t get improved if they aren’t broken. (How many times have you said “I’ll come back and fix this code later”? Yeah.) Warnings fester and grow on each other, until they cause a real breakage. It’s an inescapable evil of building software with finite resources.

If a warning isn’t worth stopping the build over — it’s not worth checking for in the first place.

Use the Latest Tools

Specifically, if you aren’t using Snow Leopard and Xcode 3.2 to build your Objective-C code, you are crazy. Trust me, painless static analysis is worth upgrading for. It catches maddening memory leaks, not just trivial type errors, like adding an int to an NSArray, that you would catch immediately.

December 7, 2009

Dot Syntax Solution

Filed under: Cocoa,Design,Objective-C,Programming,Usability | , , , ,
― Vincent Gable on December 7, 2009

Surprisingly, the addition of dot syntax to Objective-C 2.0 has been a major source of controversy. I wonder if there’s some kind of Bike Shed effect at work here: the problem dot-syntax causes is trivial1; while the clarity it brings to code is minor. So it essentially boils down to aesthetics. (For the record, I like the dot, even with it’s current flaws, but I don’t believe it’s worth fighting for).

The Actual Problem

The problem is that when you see a.b = c; you don’t know if it’s:

  1. Assigning the b field of a struct to c. This basically compiles down to one move instruction.
  2. Invoking the -setB: method on an Objective-C object. By convention -setB: should update the b property of the object to hold the value c, and nothing else. But it might have side effects, or be really slow.

A Solution

Using a different symbol to access Objective-C properties would remove all ambiguity. Nobody would mistake a@b = c; as assigning to a C-struct. It’s clearly an Objective-C construct.

But personally, I’m not a big fan of the @ character. It’s ugly; it’s noisy; there’re just too many lines in it. I think U+25B8 ‘BLACK RIGHT-POINTING SMALL TRIANGLE’ would make a better choice,

obj▸property = value;

And since ‘▸’ can’t be part of a valid C identifier, you can basically preprocess your code with s/▸/./, then compile it with existing tools.

Of course, it doesn’t matter what character(s) is picked, so long as it’s clearly different from existing C syntax; and you have a way of replacing it with a . before building it.

1 I’ve heard experienced developers complain that dot-syntax = a steeper learning curve for newbies, and that it can be confusing, but I haven’t actually seen one come out and say ‘I spent X hours debugging a problem that I couldn’t see because of it’. The fact is, any situation that dot-syntax would obscure is already pathological. In the end I just can’t see dot-syntax mattering much.

June 15, 2009

Ignoring Just One Deprecated Warning

Switching projects over to iPhone OS 3.0 means discovering that functions I’m using are deprecated. Occasionally there isn’t a totally straightforward replacement, and the best thing to do is to file a bug/TODO/note for myself, and ignore the warning until a later version, when major refactoring will be possible. But bitter experience has taught me to have Xcode treat warnings as errors1, so it’s necessary to trick the compiler into ignoring the warning for things to build.

-Wno-deprecated

The -Wno-deprecated flag tells GCC to suppress warnings about deprecated code. But adding it to an Xcode project means you won’t get useful warnings about other depreciated code.

You could file a bug telling yourself to turn that warning back on after the deprecated functionality has been updated. That should work just fine. But it feels like bad project hygiene to me.

Casting and Protocols

Type casting is a dangerous old-C technique that’s earned its infamy. But it’s undeniably fitting to use a deprecated language feature to get deprecated code to build. The basic idea is to declare a protocol that includes the method you want to suppress warnings for,

@protocol DeprecatedHack
- (void) myDeprecatedMethod;
@end

then just cast your objects so the compiler thinks they implement the protocol,

[foo myDeprecatedMethod]; //warnings
[(id<DeprecatedHack>>)foo myDeprecatedMethod]; //no warnings

Although having to declare a protocol is somewhat heavyweight, it leaves a nice artifact in the code reminding you to replace deprecated functionality.

Protocols Not Required

Sometimes just casting to id is enough. This happens if another object has a non-deprecated method with the same name.

1For experimental or prototyping projects I let warnings slide. But in the main project I always treat warnings as errors. Ignoring them in production code has never worked — warnings fester and grow on each other.

Because Objective-C is so dynamic, there are many errors that the compiler can warn you about, but can’t be totally sure are errors. For example, methods can be added to a class at runtime, so if you call -someMethodThatDoesNotExistAnywhere, the compiler will warn you that something is up, but won’t stop the build, because the necessary code could magically appear at runtime. Of course, 99% of the time, it’s me accidentally using count when I meant length, etc. What I’m really trying to say here is that treating warnings as errors is an even better idea in Objective-C.

March 13, 2009

(Always) Showing a Window on Application Switch

Filed under: Cocoa,MacOSX,Objective-C,Programming | , ,
― Vincent Gable on March 13, 2009

Keith Lang said all Mac applications should show a window when you switch to them via command-tab or gestures. I agree. I do think it is best to show nothing when the last window is closed; otherwise closing a window might mean more stuff in your face, not less. But when context-switching back into an application I can’t think of a good reason why applications shouldn’t have something up that you can interact with right now.1

This is the behavior you get when switching between applications by clicking their icons in the dock. It’s unfortunate that you have to do more work for your application to behave consistently no matter how it’s switched-to. Here’s how I’ve done this in IMLocation,

In my NSApplication delegate I implemented - (void)applicationDidBecomeActive:(NSNotification *)aNotification to check if no windows were visible, and if so, put something up. Here’s the exact code I use, replace editCurrentLocation: with what’s right for you:

- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
	[self displayLocationWindowIfNoWindowIsOpen];
}
- (void) displayLocationWindowIfNoWindowIsOpen
{
	NSArray *visibleWindows = [[NSApp windows] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"isVisible == YES"]];
	if(IsEmpty(visibleWindows))
		[self editCurrentLocation:nil];
}


1Xcode, doesn’t put up anything when you click on it’s icon and you have turned off the “Getting Started” splash screen. This makes a bit of sense, because Xcode is a project editor, not a document editor. Projects are collections of many files, and having an “untitled” default one does not make sense. But by default Xcode shows a window, the splash screen. And there is an argument that it should show an empty file, like an Emacs “scratch buffer”.

February 5, 2009

Reverse Engineering Inter-Process Communication

Filed under: Interface Builder,MacOSX,Reverse Engineering | ,
― Vincent Gable on February 5, 2009

Matt Gallagher tells how he reverse engineered the link between Xcode and Interface Builder. Very interesting, I learned a lot. I’ve done essentially the same thing with iChat. (And in retrospect it might have been a bad idea, because it’s broken on Snow Leopard).

December 28, 2008

Fast Enumeration In Objective-C 1.0

Filed under: Cocoa,MacOSX,Objective-C,Programming,Sample Code | , ,
― Vincent Gable on December 28, 2008

I have used ForEach.h to do “Fast Enumeration” in Mac OS X 10.4 “Tiger”, without any problems. You must set the “C Language Dialect” in Xcode to C99 for it to work. Credit to Michael Tsai for the code, you can find other implementations of it on his website.

With ForEach.h you can do:

#import "ForEach.h"

foreach(thing, collection) {
   /*do stuff with thing*/
}

foreacht(NSString, name, allNames)
   ;//name is typed as an NSString*

With a large collection, the foreach macro should be faster then using NSEnumerator or objectAtIndex:, because it calls the nextObject function directly, without going through Objective-C’s message sending. I have not benchmarked it, because I haven’t had a reason to optimize the mechanics of my for-loops, so I don’t know by how much. But it should give you the fast in Fast Enumeration.

If you can’t use Objective-C 2.0’s Fast Enumeration (requires Leopard or, iPhone), then I highly recommend ForeEach.h.

December 22, 2008

Resources in Unit Tests and Other Frameworks

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming,Sample Code | , , , ,
― Vincent Gable on December 22, 2008

To load a resource inside a unit test or other bundle, do:

NSBundle *unitTestsBundle = [NSBundle bundleForClass:[self class]];
NSString *pathToResource = [unitTestsBundle pathForResource:name ofType:fileExtension];

[NSBundle mainBundle] points to the bundle for the current executable, so it’s handy in an application (where it will point to your .app bundle). But since unit tests are loaded into another program or test-harness to run, it’s not appropriate to use it in a unit test.

December 8, 2008

C Comment Trivia

Filed under: Bug Bite,C++,Objective-C,Programming | , ,
― Vincent Gable on December 8, 2008

//I'll bet \
you \
didn't \
know \
you \
could \
comment \
like \
this \
in \
C/C++/Objective-C

Well, you can. Finding out was a lot of fun, believe me.

At some point, I’m not sure when, I unknowingly put a ‘\’ at the end of a block of // comments. That commented out the method-call the block was referring to. As you might guess from the fact that it had a big comment talking about why it was there, this was an important method call. I spent more time then I want to admit debugging and staring at my code trying to see the problem. Finally I noticed “hey, the color of that code is like a comment, even though it’s not in a comment”.

The More You Know!

November 24, 2008

How To Space Your Code For Maximal Interoperability

Filed under: Design,Programming,Quotes,Usability | , , , , ,
― Vincent Gable on November 24, 2008

The new rule for indentation and alignment: use tabs for achieving an indentation level, spaces for character alignment within an indentation level.

Christopher Bowns (and independently Peter Hosey)

The arguments make total sense to me. Here’s hoping for better IDE support in the future. Unfortunately, (though interestingly), according to Steve Yegge, indentation is very hard:

I would have been publishing this article at least a month ago if it weren’t for indentation. No, six weeks, mininum.

See, I thought that since I had gone to all the thousands of lines of effort to produce a strongly-typed AST (abstract syntax tree) for JavaScript, it should therefore be really easy to do indentation. The AST tells me exactly what the syntax is at any given point in the buffer, so how hard could it be?

It turns out to be, oh, about fifty times harder than incremental parsing. Surprise!

Here’s a forward-looking (somewhat contrary) opinion,

Soft-wrapped code (leaving a long line long, and letting the IDE handle the spacing) also appears to be the direction that Apple are heading and they tend to drag a lot of Mac programmers along in their wake.

Matt Gallagher

Older Posts »

Powered by WordPress