(((1 << 3) & (~0xF | (3 >> 1) & (~0xFFED << 4))) | ~(7 + 0xDEADBEEF << 7) >> 5) >> 5 ^ (0xDE ^ (~0xF32 >> (5 | 74 >> 2)))

NSCopying and Mutability

Devin Lane | Cocoa Yups and Nopes | Friday, April 17th, 2009

In the Cocoa frameworks, it is common to find mutable and immutable versions of classes that store data, such as strings, dictionaries, and arrays. Most of these classes also implement the NSCopying informal protocol, and those with mutable varients implement the NSMutableCopying protocol. These protocols specify methods for obtaining immutable and mutable copies of an object. These copying methods should be implemented such that the copy can return an instance of a subclass, to allow for subclasses to copy their specific instance variables.

There are situations, however, that can result in the inability of a subclass to do so. Consider NSURLRequest:

@interface NSURLRequest : NSObject <NSCoding, NSCopying, NSMutableCopying>

An immutable class, but one that implements NSMutableCopying, it responds directly to the -mutableCopyWithZone:(NSZone *)zone method that returns a mutable url request, an instance of NSMutableURLRequest. While this isn’t a problem in itself, it becomes an issue when this method is not re-implemented in NSMutableURLRequest.

– Nope: Implement the NSMutableCopying protocol only in your immutable class.

The implementation of -mutableCopyWithZone:(NSZone *)zone in the immutable class must certainly hard-code the name of the mutable class — it cannot be aware of any external subclasses of the mutable class. This means that asking for a mutable copy of the immutable class creates an instance of the known mutable subclass. Consider the following example:

@interface MyMutableURLRequest : NSMutableURLRequest {} @end

MyMutableURLRequest *request = [MyMutableURLRequest requestWithURL:url];
request = [request mutableCopy];

In this case, the object returned from -mutableCopy will be an instance of NSMutableURLRequest instead of the expected MyMutableURLRequest.

– Nope: Hardcode class names in -copyWithZone: and -mutableCopyWithZone:

Hardcoding class names serves to block subclassers from subclassing the copy methods without dirty hacks.

+ Yup: [Re]Implement the NSMutableCopying protocol in your mutable class.

By doing this, the class name doesn’t have to be hard-coded (in the mutable class), and so a subclasser can simply call [super mutableCopy] and then copy their specific instance variables.

+ Yup: Use [self class] in -copyWithZone: and -mutableCopyWithZone:

By using [self class], an object of the subclass type will be allocated.

Readable If Statements

Devin Lane | Coding Yups and Nopes | Friday, April 17th, 2009

To kick of the Coding Yups and Nopes section, I’ll start with something simple. There are a set of things to do, and a set of things to avoid. For each thing, there are one or more reasons justifying its classification. These reasons are ordered by descending importance and increasing subjectivity.

– Nope:

if (condition) doWork();
else doOtherWork();
  • If you’re stepping through with a debugger (I used gdb), it is difficult to tell when stepping over the line if the statement is executed. To do so you must determine the value of condition, or determine if the function was called based on its side effects.
  • If you add an additional statement to the false case, it’s possible that braces may be forgotten, leading to incorrect operation.
  • Assuming the reason for putting both condition and statement on one line was to use less lines, the benefits of this are negated by the decreased readability of such a statement. By putting both condition and statement on one line, searching for a specific condition becomes more difficult.
  • Assuming other parts of your code are scoped and indented, this breaks that pattern.
if (condition) {
    doWork();
} else doOtherWork();
  • Similar to the above case. Basically this is inconsistent and has none of the advantages of either method.
if(condition){
    doWork();
}
  • This is a pure spacing issue. if is not a function, please do not call it as one. Also, that brace is squashed against that parentheses, give it some room! Skimping on spacing issues like this while writing makes it harder to read later.

+ Yup:

if (condition) {
    doWork();
} else {
    doOtherWork();
}
  • The perfect if-else statement. Well spaced, condition and statement on separate lines.
if (error) return;
if (error) break;
if (error) continue;
  • When used only for error/early exit conditions, these help to condense code so that the reader can quickly get to the meat of a function.
  • The statements and the condition are on one line because I do not consider the flow control statements return, break, and continue to contribute useful work, such that it should be scoped in braces and on its own line.

Window Resizing on Resolution Change

Devin Lane | App Yups and Nopes | Thursday, April 16th, 2009

This post kicks off the “App Yups and Nopes” section in which I’ll post both good and bad things I see applications doing. This differs from the other Yups and Nopes sections in that it talkes specifically about observed application behavior. My intent is to show why a specific behavior is undesirable, then present a solution.

In this situation, I connect my laptop to a projector to watch a movie. My screen resolution changes to match that of the projector. I see applications with the following behaviors:

– Nope: Resize application windows to fit on screen, regardless of window or application visibility.

The goal of resizing an application window on screen resolution change is to make sure the window is placed so that the user is able to manipulate it (move and resize.) An application is only required to resize and reposition windows that are actually visible. If a window is offscreen or the application is hidden, the window size and position should not be modified. When an offscreen window or a window of a hidden application is modified in this way, useless computation results. If the window cannot be seen, what use is there in constraining its bounds?

+ Yup: Resize application windows as they are made visible, making only the smallest change necessary to satisfy visibility and interaction requirements.

A common trick I use before connecting an external monitor of smaller resolution is to hide all applications — for most applications this prevents their window state from being altered. In this way when I have finished using the projector, I can unhide these applications and continue using them with a window state identical to before the resolution change. This works great for applications that implement correct window resizing behavior. Most Cocoa applications do this correctly by default. Noted offenders are iTunes and iPhoto, both of which require me to pointlessly resize their windows after the resolution is restored.

Note also that only the height must be constrained to the visible screen height — windows are allowed to be wider than the screen. Furthermore, it is not necessary to reposition the window such that its entire contents are visible — windows can hang off the edge of the screen on the left and right sides. This, of course, becomes more complicated when multiple displays are attached as these restrictions change.

Powered by WordPress | Theme by Roy Tanck, modifications by Devin