Key-Value Observing Done Right. Again.
May 21, 2010 04:36 PM
| Cocoa, Development, Mac
| Permalink
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:
Inspired by Mike's and Andy's writings and work, I have come up with my own implementation: HHKeyValueObserver.
Retain cycles may be avoided by referring to the observed object by the way of observationInfo.observee.
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
May 19, 2010 10:20 AM
| Cocoa, Development, Mac
| Permalink
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.
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.
HHAutoHidingWindow
May 5, 2010 10:06 PM
| Cocoa, Development, Mac
| Permalink
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.
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.
Automatically releasing retained @property values
January 12, 2010 04:03 PM
| Cocoa, Development, Mac
| Permalink
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.
- (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)
Elephant Back Ride
Houdah Software now has an official blog. We will discuss news, tips & tricks regarding our Mac & iPhone products: HoudahSpot, HoudahGeo, HoudahGPS, ACTCurrency, ACTPrinter, ACTSudoku, …
My personal blog will no longer include product or sale announcements for Houdah Software. It will instead focus on subjects related to software development. I will continue to announce open source code provided by Houdah Software. I may also publish the occasional movie review.
BTW, you owe it to yourself to go see Avatar. It is spectacular. Though the story may be somewhat predictable, this movie combines spectacular images with some excellent story telling.
My personal blog will no longer include product or sale announcements for Houdah Software. It will instead focus on subjects related to software development. I will continue to announce open source code provided by Houdah Software. I may also publish the occasional movie review.
BTW, you owe it to yourself to go see Avatar. It is spectacular. Though the story may be somewhat predictable, this movie combines spectacular images with some excellent story telling.
HoudahSpot 2.6
HoudahSpot 2.6 improves integration with other applications by the way of Mac OS X services. HoudahSpot itself provides a "BlitzSearch" and a "Search Location" service.
HoudahSpot 2.6 brings many more enhancements:
▪ HoudahSpot 2.6 adds toolbar buttons for "Add ALL Group", "Add ANY Group" and "Add NONE Group".
▪ A "Search Location in HoudahSpot" service is now provided in the Finder as well as in other applications working with files.
▪ Users may narrow down a search by command-clicking folders in the path control at the bottom of the window.
▪ The grid view now has a slider to adjust icon size.
▪ The grid view now provides the same contextual menu as the list view.
▪ One may now see the MDQuery string passed to Spotlight.
▪ Clicking a "+" button on a criterion row duplicates the current row. This makes it easier than ever to refine a search.
▪ HoudahSpot 2.6 improves integration with other applications through Mac OS X services. Services are also available for the contextual menus.
▪ The BlitzSearch service is now enabled by default under Snow Leopard.
▪ Result list font size is adjustable and preference is persisted.
▪ HoudahSpot 2.6 features new toolbar and preferences icons by Lars Herrmann.
▪ The keyboard shortcut for item deletion has been changed to match other applications.
For details, have a look at the screencast.
HoudahSpot 2.6 brings many more enhancements:
▪ HoudahSpot 2.6 adds toolbar buttons for "Add ALL Group", "Add ANY Group" and "Add NONE Group".
▪ A "Search Location in HoudahSpot" service is now provided in the Finder as well as in other applications working with files.
▪ Users may narrow down a search by command-clicking folders in the path control at the bottom of the window.
▪ The grid view now has a slider to adjust icon size.
▪ The grid view now provides the same contextual menu as the list view.
▪ One may now see the MDQuery string passed to Spotlight.
▪ Clicking a "+" button on a criterion row duplicates the current row. This makes it easier than ever to refine a search.
▪ HoudahSpot 2.6 improves integration with other applications through Mac OS X services. Services are also available for the contextual menus.
▪ The BlitzSearch service is now enabled by default under Snow Leopard.
▪ Result list font size is adjustable and preference is persisted.
▪ HoudahSpot 2.6 features new toolbar and preferences icons by Lars Herrmann.
▪ The keyboard shortcut for item deletion has been changed to match other applications.
For details, have a look at the screencast.
MacGraPhoto - A Graphics Applications Bundle
Get 7 great graphics applications for the price of one: $39.99 instead of $251
The MacGraPhoto bundle allows Mac users to get 7 premium graphics applications for the price of one or even for free. Applications in MacGraPhoto bundle will satisfy most of imaging needs of any Mac user: image editing, applying effects, format conversion, batch processing, vector drawing, geo-tagging photos, framing them or even creating posters and postcards.
Most Mac bundles lack focus - they collect unrelated applications, and many Mac users usually need only a couple of them. MacGraPhoto bundle is focused exclusively on graphics: it is a hand-picked selection of 7 premium applications from 7 different companies. Most of these applications received Apple "Staff Pick" or Apple Design Award.
The MacGraPhoto bundle allows Mac users to get 7 premium graphics applications for the price of one or even for free. Applications in MacGraPhoto bundle will satisfy most of imaging needs of any Mac user: image editing, applying effects, format conversion, batch processing, vector drawing, geo-tagging photos, framing them or even creating posters and postcards.
Most Mac bundles lack focus - they collect unrelated applications, and many Mac users usually need only a couple of them. MacGraPhoto bundle is focused exclusively on graphics: it is a hand-picked selection of 7 premium applications from 7 different companies. Most of these applications received Apple "Staff Pick" or Apple Design Award.
One Finger Discount
One Finger Discount is a promotion inspired by the current MacHeist nanoBundle that is running for the rest of the week, offering a discount of 20%, or one fifth, the full price of the software. It is being run by Daniel Jalkut of Red Sweater Software, developer of MarsEdit and more.
TheMacSale 2 features HoudahGeo
Get 10 great Mac applications for only $49.99 at themacsale.com. The bundle includes HoudahGeo (regular single-user license).
HHDualShortcutButton updated
October 10, 2009 12:39 PM
| Cocoa, Development, Houdah, Mac
| Permalink
HHDualShortcutButton has been updated to be Cocoa only. No more Carbon code!
This makes it require Mac OS X 10.6 Snow Leopard.
This makes it require Mac OS X 10.6 Snow Leopard.