I braved the polar vortex to come down to Sandusky, OH for the always-amazing CodeMash conference. I gave a talk about Objective-C’s underpinnings in C and the like. You can find the slides on SpeakerDeck, and the slides and code on the unofficial GitHub repository for the conference. Thanks for coming, everyone!
Tag: Objective-C Runtime
Slides: Understanding Objective-C Inside and Out from CocoaHeads Ann Arbor
Last night I gave the Understanding Objective-C Inside and Out talk at CocoaHeads Ann Arbor. You can find my slides on SpeakerDeck.
We had a really great turnout—CocoaHeads Ann Arbor is almost outgrowing its space! If you’re in the SE Michigan area (or even further—there are attendees from Kalamazoo and Grand Rapids) you should come to the next meeting and learn about Auto Layout.
Slides: Understanding Objective-C Inside and Out from CocoaConf Columbus 2013
Once again I ventured south to Columbus and the always-excellent CocoaConf. My presentation was about Objective-C, and you can view the slides on Speaker Deck.
Slides: Using and Creating Images in iOS at MobiDevDay Detroit
Today was MobiDevDay in Detroit, and it was a heck of a good conference (and I’m not just saying that because Detroit Labs helped put it on). The slides from my presentation are on Speaker Deck, and you can see AmazeKit on GitHub or view its documentation. Enjoy!
Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object
Update: This post is getting some attention lately, so I’ve updated it a bit to be less incorrect.
Sometimes when you’re debugging an application, especially one that you’ve inherited, you find yourself wondering when an object is released. Autorelease pools only compound the problem, delaying the actual release until the run loop is idle. In this post, I’ll show you how to take advantage of new features in the Objective-C runtime to run arbitrary code when any object—whether it’s your own or a part of Apple’s frameworks—is deallocated.
We’ll be taking advantage of the Objective-C runtime’s new associated objects behavior. When you associate an object with another object using retain or copy semantics, the runtime automatically handles releasing it at the appropriate time. So, if we want one object to be released when another object is deallocated, we simply associate them:
[sourcecode gutter=”false” language=”objc”]id objectToBeDeallocated;
id objectWeWantToBeReleasedWhenThatHappens;
objc_setAssociatedObject(objectToBeDeallocted,
someUniqueKey,
objectWeWantToBeReleasedWhenThatHappens,
OBJC_ASSOCIATION_RETAIN);[/sourcecode]
Now, when objectToBeDeallocated
is deallocated, objectWeWantToBeReleasedWhenThatHappens
will be sent a -release
message automatically. The association policy passed as the last parameter to the function can be one of the following:
OBJC_ASSOCIATION_ASSIGN |
No memory management; the value is simply assigned. |
OBJC_ASSOCIATION_RETAIN_NONATOMIC |
Retains the object non-atomically. |
OBJC_ASSOCIATION_COPY_NONATOMIC |
Copies the object non-atomically. |
OBJC_ASSOCIATION_RETAIN |
Retains the object atomically. |
OBJC_ASSOCIATION_COPY |
Copies the object atomically. |
Obviously, using OBJC_ASSOCIATION_ASSIGN
won’t work for us, since it won’t cause the object to be retained. We also don’t want to use either of the copy policies, since we only want one copy of our objects around. For this example I’ll be using OBJC_ASSOCIATION_RETAIN
, but not over OBJC_ASSOCIATION_RETAIN_NONATOMIC
for any compelling reason.
Now that we know how to release an object when another is deallocated, we need to create an object to run arbitrary code at deallocation time. Blocks are an excellent tool for this, so I created a dead-simple class, JKBlockExecutor, to handle the running of the block:
[code language=”objc”]typedef void (^voidBlock)(void);
@interface JKBlockExecutor : NSObject {
voidBlock block;
}
@property (nonatomic, readwrite, copy) voidBlock block;
– (id)initWithBlock:(voidBlock)block;
@end
@implementation JKBlockExecutor
@synthesize block;
– (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
block = Block_copy(aBlock);
}
return self;
}
– (void)dealloc
{
if (block != nil) {
block();
Block_release(block);
}
[super dealloc];
}
@end[/code]
Now that we can pass arbitrary code to a JKBlockExecutor (and if you have a better name I’m all ears), we can make a category on NSObject to make the association for us:
[code language=”objc”]const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
@interface NSObject (JK_RunAtDealloc)
– (void)runAtDealloc:(voidBlock)block;
@end
@implementation NSObject (JK_RunAtDealloc)
– (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
[executor release];
}
}
@end[/code]
So, how do you use it? The following example prints “Deallocating foo!” when foo
is deallocated:
[objc]NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
NSLog(@"Deallocating foo!");
}];
[foo release];[/objc]
And that’s all there is to it!
Well, almost. There is one gotcha that I must warn you about: don’t access the object from within the block. There are two reasons. First, I’m not sure where in the deallocation process the Objective-C runtime releases its associated objects, so accessing the object may result in a crash. Second, if you reference the object from within the block, the block will retain the object. This causes a retain cycle where the block and the object each own each other, so neither will ever be released. If you absolutely must reference your object (at your own risk), then do it like so:
[objc]NSObject *foo = [[NSObject alloc] init];
__block id objectRef = foo;
[foo runAtDealloc:^{
NSLog(@"Deallocating foo at address %p!", objectRef);
}];
[foo release];[/objc]
Using the __block
storage qualifier on an Objective-C object causes the runtime to avoid retaining the object, since the dymanics of object retain counts inside of blocks would be far too hairy to manage automatically. Seriously, though: don’t do it unless you absolutely must.
So there you have it: a quick and dirty category on NSObject to run arbitrary code at deallocation. I don’t really see a use it for it in production code, but on those occasions when you’re debugging someone else’s memory management, this could be handy. Since it uses blocks and associated objects, you’ll need to be running Mac OS X Snow Leopard (64-bit) or later or iOS 4.0 or later.