mikeash/MAObjCRuntime

Associated Object API

texastoland opened this issue · 11 comments

Would this fit in your library?

Can you explain what it's supposed to do? In particular, I don't understand the point of using dispatch_once to set an associated object like that.

Yeah that pattern was popularized for instantiating singletons instead of checking nil. My FIIcon category snippet uses it for just that. It shouldn't cost any memory or computation until first access.

My UIView category snippet is part of an API that proxies UIAppearance selectors directly to arbitrary [sub]layers for better styling since CALayer supports CSS-like method selectors. In this case it facilitates getting arbitrary additional sublayers for fancy filters or whatever. GCD ensures they're only added as desired even if by an UIAppearance proxy.

In practice I typically only instantiate ivars once and modify their state thereafter. But I instantiate them in lifecycle methods that categories shouldn't replace. My Associated Object API provides both storage and lazy instantiation.

I'm familiar with the pattern, but this isn't a singleton. You're using a global dispatch_once to control the adding of an associated object to a single arbitrary instance in your -[UIView sublayer]. This doesn't make any sense to me, and providing an API that takes a dispatch_once_t * in general does not seem like the right approach.

Ah quite right my sublayer one is messed up. I'll fix it. In essence it needs a unique key per instance.

That doesn't really address the overall concern, though. What is the point of using dispatch_once to gate access to an associated object like this? dispatch_once is generally used for globals, but associated objects are inherently per-instance, so it seems like a complete mismatch.

Although it's not a singleton it is truly a multiton. Because categories can't have ivars the only alternative is still a nil guard or + load() without lazy instantiation. GCD just "feels" better to me. It's funny I ran across your blog googling about it just now. What would you do besides a nil guard? PS thx :)

The thing is that I don't see how the GCD solution works. There appear to only be two cases:

  1. There's a single object, ever.
  2. There are multiple objects.

Case 1 is basically the standard singleton pattern and can be solved without associated objects, by just using a global variable. In case 2, dispatch_once doesn't work, because you need to run the code more than once (i.e. once for each object). Case 1 can use dispatch_once but doesn't need associated objects. Case 2 needs associated objects but can't use dispatch_once. So I don't see where it's ever useful to have an API that combines them like this. Can you give an example of where it would be useful?

Wow what's ridiculous is I'm using a static variable for a singleton dictionary elsewhere in that same class. Guess I had tunnel vision. If I have a reasonable multiton solution I'll share. My use case is implementing category properties like my sublayers without nil checks. Closing ticket; great feedback.

OK, cool, glad we figured out what the disconnect was. I think you'd want to use associated objects still, but I'm not sure if there's a good way to lazily initialize them. You can do a check-and-set, but it's not thread safe without external synchronization....

I tried concocting a strategy to use the pointer storage returned by objc_getassociatedobject(self, key) to store a dispatch_once_t and failed. I just wrapped it in @synchronized for now.

Just wanted to note that anytime I've googled about Obj-C sticking points your blog has unanimously been the authoritative source of documentation. If you had a book I'd read it :neckbeard: