Skip to content

Instantly share code, notes, and snippets.

@ddribin
Created March 14, 2013 03:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ddribin/5158614 to your computer and use it in GitHub Desktop.
Save ddribin/5158614 to your computer and use it in GitHub Desktop.
Evil KVO context hack using macros + C99 compound literal syntax.
// Building upon: http://www.dribin.org/dave/blog/archives/2008/09/24/proper_kvo_usage/
// Defines a unique KVO context by taking the address of a 2-element string array.
// Using __FILE__ ensures the address is unique across source files, even with link time optimization.
#define DDDefineContext(_X_) static void * _X_ = &(const char *[] ) {#_X_, __FILE__}
// Example Definition
DDDefineContext(MyFooContext);
// Example Usage. No need for &MyFooContext to make it unique.
- (void)startObserving
{
[_ivar addObserver:self forKeyPath:@"foo" options:0 context:MyFooContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// In a debugger, use `p *(char **)context` to dump the context
if (context == MyFooContext) {
// foo changed
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)stopObserving
{
[_ivar removeObserver:self forKeyPath:@"foo" context:MyFooContext];
}
@kylesluder
Copy link

I feel like I should point you at @mikeash's incredibly clever use of C:

static const void *MyFooContext = &MyFooContext;

MyFooContext is initialized at load time with a pointer to itself.

@ddribin
Copy link
Author

ddribin commented Mar 14, 2013

Yeah, but I really like being able to print out the context in OVFKP while debugging and get something useful.

@0xced
Copy link

0xced commented Mar 14, 2013

It looks like you missed a mention ;-)

@ddribin Re http://www.dribin.org/dave/blog/archives/2008/09/24/proper_kvo_usage/ You can correlate the context address with a particular context variable: (gdb) info symbol context

Or with lldb (given that you defined MyFooContext as Kyle described):

(lldb) image lookup -a `context`
      Address: MyApp[0x00026258] (MyApp.__DATA.__data + 4)
      Summary: MyFooContext

@ddribin
Copy link
Author

ddribin commented Mar 14, 2013

Oh… nice! Yeah, I didn’t know about the syntax. That does work well. Less hacky, too. Thanks!

@kylesluder
Copy link

Because gist comment markdown sucks, I didn't realize you folks were referring to the shell-like backtick syntax. I was worried vararg macros were somehow involved…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment