Pierre Bernard

My little hideout on the net

December 24
November 24
October 24
September 24
August 24
July 24
June 24
May 24
April 24
March 24
February 24
January 24
December 23
November 23
October 23
September 23
August 23
July 23
June 23
May 23
April 23
March 23
February 23
January 23
December 22
November 22
October 22
September 22
August 22
July 22
June 22
May 22
April 22
March 22
February 22
January 22
December 21
November 21
October 21
September 21
August 21
July 21
June 21
May 21
April 21
March 21
February 21
January 21
December 20
November 20
October 20
September 20
August 20
July 20
June 20
May 20
April 20
March 20
February 20
January 20
December 19
November 19
October 19
September 19
August 19
July 19
June 19
May 19
April 19
March 19
February 19
January 19
December 18
November 18
October 18
September 18
August 18
July 18
June 18
May 18
April 18
March 18
February 18
January 18
December 17
November 17
October 17
September 17
August 17
July 17
June 17
May 17
April 17
March 17
February 17
January 17
December 16
November 16
October 16
September 16
August 16
July 16
June 16
May 16
April 16
March 16
February 16
January 16
December 15
November 15
October 15
September 15
August 15
July 15
June 15
May 15
April 15
March 15
February 15
January 15
December 14
November 14
October 14
September 14
August 14
July 14
June 14
May 14
April 14
March 14
February 14
January 14
December 13
November 13
October 13
September 13
August 13
July 13
June 13
May 13
April 13
March 13
February 13
January 13
December 12
November 12
October 12
September 12
August 12
July 12
June 12
May 12
April 12
March 12
February 12
January 12
December 11
November 11
October 11
September 11
August 11
July 11
June 11
May 11
January 10
December 09
November 09
October 09
September 09
August 09
May 09
April 09
March 09
February 09
January 09
November 08
October 08
September 08
June 08
May 08
April 08
March 08
February 08
January 08
December 07
November 07
October 07

Key-Value Observing Done Right. Again.

I love using KVO for all sorts of things: side-effect, flagging UI as dirty, resetting caches, …

Writing the observeValueForKeyPath:ofObject:change:context: method has long since become tedious. So I created a TextExpander snippet to write it for me.

Still, I don't quite like it relying of string comparisons (which I use for context). And I regularly find myself forgetting to unregister observers.

Mike Ash wrote a interesting blog post where he makes a couple of good points against the current KVO API. The most important of which, I think, is the fact unregistering an observer might actually break behavior upon which the superclass relies.

Andy Matuschak has proposed a very convenient API which uses blocks to handle observation callbacks. While I love this solution, I found it to still have a couple of drawbacks:

  • Andy's KVO+Blocks requires Mac OS X Snow Leopard. It relies not only on blocks, but also on associated objects and Grand Central Dispatch.
  • Code is not always easer to read when the callback block is written where it is registered. At times, I would prefer a traget+action setup
  • KVO+Blocks make it all too easy to create retain cycles: referencing an instance variable from within the block retains the owning object.

Inspired by Mike's and Andy's writings and work, I have come up with my own implementation: HHKeyValueObserver.

  • Works on both Leopard and Snow Leopard. Relies on HHAssociatedObjects
  • Target action mechanism with the following signatures: actionWithInfo:change: or actionWithInfo:
  • Uses blocks where available
  • Unregisters automatically on dealloc of the observer

Retain cycles may be avoided by referring to the observed object by the way of observationInfo.observee.

Comments

HHAssociatedObjects

Mac OS X 10.6 introduced associated objects by the means of objc_getAssociatedObject and objc_setAssociatedObject. These provide a very convenient method for attaching object values to random objects. Associated objects can conveniently share the lifespan of the object they are associated with.

One situation where associated objects come in especially handy is when writing categories. Associated objets may be used be category methods to store state. It's the closest thing we got to adding instance variables.

The catch being that many projects still need to support Leopard. HHAssociatedObjects implements the concept of associated objects to support Leopard and Snow Leopard. Where available, the objc_getAssociatedObject and objc_setAssociatedObject methods are used. Elsewhere a NSMapTable is used to store associate objects.

HHAssociatedObjects are made available as a category on NSObject. I settled on the same API as Andy Matuschak. On Snow Leopard the implementation is actually the same as Andy's. HHAssociatedObjects adds a Leopard compatible implementation.
Comments

HHAutoHidingWindow

For the next version of HoudahSpot, I am implementing a window which docks to the side of the screen where it shows and hides as needed. After looking into several implementations, I came up with my own. Seeing this may come in handy to some, I'd like to share this bit of code with you.

HHSlidingWindow allows for docking a window at an edge of the main screen. From there it may slide in and out of visibility. Its subclass HHAutoHidingWindow
provides automatic showing of the window as the mouse hits the screen edge where the window is hiding. The implementation is actually pretty straightforward.
It relies solely on tracking areas. No polling is done.
Comments

Automatically releasing retained @property values

I subscribe to the opinion, that setters should not be called in constructors nor in destructors. This negates some of the benefits of @synthesize accessors. Indeed, one needs to keep the dealloc method in sync with the setter semantics. Our dealloc methods thus look like this:

- (void)dealloc
{
// Retained properties
[_firstProperty
release], _firstProperty = nil;
[_thirdProperty
release], _thirdProperty = nil;

// Assigned properties
secondProperty =
nil;

[
super dealloc];
}

This is repetitive and error-prone. Luckily, we may generate @synthesize instructions as well as destructors.

The alternative, is to use introspection to dynamically determine how the various properties need to be freed. For this, I suggest a category on NSObject:

@implementation NSObject (PropertyDealloc)

- (
void)deallocProperties
{
Class class = [self class];
unsigned int pCount;
objc_property_t *properties = class_copyPropertyList(class, &pCount);

for (unsigned int i = 0; i < pCount; i++) {
objc_property_t property = properties[i];
NSString *propertyAttributes = [[[NSString alloc] initWithUTF8String:property_getAttributes(property)] autorelease];
NSArray *propertyAttributeArray = [propertyAttributes componentsSeparatedByString:@","];
BOOL isRetained = NO;

for (NSString *string in propertyAttributeArray) {
isRetained = isRetained || [string
isEqual:@"&"] || [string isEqual:@"C"];
}

if (isRetained) {
NSString *variableName = nil;
NSString *lastProperty = (NSString*)[propertyAttributeArray lastObject];

if ([lastProperty hasPrefix:@"V"]) {
variableName = [lastProperty
substringFromIndex:1];
}

if (variableName != nil) {
Ivar ivar = class_getInstanceVariable(class, [variableName UTF8String]);
id value = object_getIvar(self, ivar);

object_setIvar(self, ivar, nil);
[value
release];
}
}
}

free(properties);
}

@end

Usage is extremely simple:

- (void)dealloc
{
[
self deallocProperties];

[
super dealloc];
}

This post was inspired by Vincent Gable.
Comments (3)

HHDualShortcutButton updated

HHDualShortcutButton has been updated to be Cocoa only. No more Carbon code!

This makes it require Mac OS X 10.6 Snow Leopard.
Comments

Sample use of HHBlockPerform

HHPerformBlock SetterBlock(id inValue, NSString *inKey)
{
HHPerformBlock block = ^(id owner) {
[owner
willChangeValueForKey:inKey];
[owner
associateValue:inValue withKey:inKey];
[owner
didChangeValueForKey:inKey];
};

return [[block copy] autorelease];
}

/* ... */

- (
NSNumber*)progressMinValue
{
return [self associatedValueForKey:@"progressMinValue"];
}

- (
void)setProgressMinValue:(NSNumber*)inValue
{
[
self performOnMainThreadWait:YES block:SetterBlock(inValue, @"progressMinValue")];
}
Comments

HHBlockPerform revisited

The first post on the subject prompted Ben to comment: "Helpful tip: Just capture the object being messaged using the block's scope. No need for the extra "owner" parameters and whatnot." Right he is.

typedef void (^HHPerformBlock)();


@interface NSObject (HHBlockPerform)

- (
void)performAfterDelay:(NSTimeInterval)delay block:(HHPerformBlock)block;
- (
void)performOnMainThreadWait:(BOOL)wait block:(HHPerformBlock)block;

@end


@implementation NSObject (HHBlockPerform)

- (
void)performAfterDelay:(NSTimeInterval)delay block:(HHPerformBlock)block
{
[
self performSelector:@selector(runBlock:) withObject:[block copy] afterDelay:delay];
}

- (
void)performOnMainThreadWait:(BOOL)wait block:(HHPerformBlock)block
{
[
self performSelectorOnMainThread:@selector(runBlock:) withObject:[block copy] waitUntilDone:wait];
}

- (
void)runBlock:(HHPerformBlock)block
{
block();

[block
release];
}

@end

It does not get any simpler than this:

[self performAfterDelay:0.2f block:^ {
[containerView
replaceSubview:currentNavigationBarView with:navigationBarView];
}];

[UPDATE October9, 2009] While I agree that the (id owner) argument is not strictly necessary, I do prefer that API and will keep using it. Indeed, it allows for reusable blocks which refer to owner much like you would refer to self in the delyed method call.
Comments

Xcode user script: PropertyFromInstanceVariable

Wrote some Perl today. No, I don't know Perl. Turns out it is good at handling strings.

I stumbled upon a blog post on Cocoa with Love. Matt Gallagher has devised this excellent Xcode user script to generate @property declarations and @synthesize statements from variable declarations. This is triple great:

1. The script will save me quite some typing
2. I had never noticed the Xcode script menu
3. Matt found a nifty way around limitations of those user scripts

So I grabbed the script. Installed it. Then I figured, I could improve upon the existing script. My changes include:

1. Generates the necessary statements in the dealloc method
2. Detects variable types and tries to be smart about setter semantics
3. Supports underbar variable names

Shortly after I had published my version of the code to my own Code page, Mike Schrag pointed me to his forked version of Matt's script. He had made many of the same enhancements. Moreover he had taught the script to handle multiple varaibles in one pass.

Merging my version and Mike's I created my very first project on github. The new version improves on Mike's by reducing the number of calls to AppleScript. It retains all my previous enhancements. And hopefully also retains Mike's changes. It is available on github, as well as on my own Code page. Enjoy!
Comments (1)

NSObject (HHBlockPerform): delayed block executions

typedef void (^HHPerformBlock)(id owner);


@interface NSObject (HHBlockPerform)

- (
void)performAfterDelay:(NSTimeInterval)delay block:(HHPerformBlock)block;

@end


@implementation
NSObject (HHBlockPerform)

- (
void)performAfterDelay:(NSTimeInterval)delay block:(HHPerformBlock)block
{
[
self performSelector:@selector(runBlock:) withObject:[block copy] afterDelay:delay];
}

- (
void)runBlock:(HHPerformBlock)block
{
block(
self);

[block
release];
}

@end
Comments (1)

HHValidatedButton: User interface validation for NSButton

According to the Cocoa User Interface Validation documentation: "The protocols NSUserInterfaceValidations and NSValidatedUserInterfaceItem provide a standard way to validate user interface items—that is, to set their state as appropriate for the current application context".

Unfortunately, automatic user intreface validation is provided only for menu items and toolbar items. Wouldn't it be great if NSButton could also benefit from this set-up?

That's what HHValidatedButton implements. It is a drop-in subclass of NSButton. It channels validation through validateButton: and validateUserInterfaceItem:.
Comments (2)

HHDualShortcutButton

Long time no blogging. Sorry about that.

I'll make it up to you by publishing a fresh bit of Cocoa code. HHDualShortcutButton is a NSButton subclass which may respond to 2 different keyboard shortcuts. You may know this from save confirmation sheet that pops up when you try to quit an application with dirty document. The Save button triggers its action on both Enter and command-S.

Moreover the HHDualShortcutButton will display one of its shortcuts as label when the command key is held down. This used to exist in save sheets. Now AppleWorks is the only example I can find. Currently this works only for alphanumeric shortcuts. I have not yet figured out how to represent special characters like the Return key, ...

Enjoy!
Comments

HHusbObserver & HHserialObserver

I have finally published my first bit of open source Cocoa code: HHusbObserver & HHserialObserver.

Previously I have published a series of WebObjects code snippets. Lately I have kicked off a major open source project: Houdah WebObjects Frameworks.

The fact remains that up to now I had not yet deemed any of my Cocoa code worthy of being published. HHusbObserver & HHserialObserver is not code to be particularly proud of. Writing it however required a lot of documentation reading and experimenting. Thus I hope for this to save other some valuable time.
Comments

Leopard compatibility

The official release of Mac OS X 10.5 Leopard is only hours away. Rumor sites actually report some got lucky and received their copies early. Obviously the press got their copies too. Developer - paying ADC members - unfortunately still haven't seen the GM build.

I have submitted some nasty feedback to ADC - suggesting I will ask for a refund if they fail to provide early access to Leopard. At least I got them scared to the point of calling me. Trouble is that the person on the phone couldn't (wouldn't ?) understand the issue. She thought I was asking whether ADC members will receive a copy of the release DVD. It turns out that isn't decided either. Up to know this was a given to me.

The upshot is that I am unable to make a definite statement as to the Leopard compatibility of HoudahGeo and HoudahSpot.

The good news is that - as of the latest Leopard pre-release build - HoudahGeo was working pretty well under Leopard. There is only a small glitch in the way sheets are displayed. They ought to have rounded corners, but Leopard seems to insist on drawing square corners around the round ones. This will be fixed in a forthcoming update.

HoudahSpot, on the other hand, does not work at all on Leopard. That news isn't all bad though. HoudahSpot was in for a complete rewrite anyway. Thus HoudahSpot 2.0 will be a major update and require Mac OS X 10.5 Leopard.

Today I have released HoudahSpot 1.5 (Tiger Edition) as freeware. Thus: Tiger users get HoudahSpot for free. As they upgrade to Leopard they will need to purchase a license or recycle a previously bought 1.x license.
Comments