How is Associative Reference implemented?

后端 未结 2 1435
清歌不尽
清歌不尽 2021-01-13 00:53

I saw a very good sample here: Subclass UIButton to add a property

What is it? You can\'t add object to a category. But now with this trick you can.

So what

相关标签:
2条回答
  • 2021-01-13 01:08

    With the Associative References trick, you're not actually adding any instance data to the UIButton object. Instead, you're using a totally separate Cocoa facility to create a new dictionary mapping (or associating) existing UIButton objects with data that's stored elsewhere in the heap.

    You could do exactly the same thing without using Cocoa's Associative References; it would just be even uglier and probably less efficient. It would go something like this, in Objective-C++. (I'm not even going to try to write it in Objective-C, because CFMutableDictionary and NSMutableDictionary both have the wrong behavior on a couple of levels, and I'm not going to write the whole thing from scratch. However, C++'s std::map can't be used with __weak references the way I want to use it, so I'm falling back on this inefficient std::vector algorithm. For those unfamiliar with C++: std::vector is roughly equivalent to an NSMutableArray, except that you get to choose whether it retains its contents.)

    The point is that the UIButton objects aren't being changed; what's changing is the contents of this additional dictionary. The property getter and setter simply know how to look things up in that dictionary so that it appears as if the UIButton has a new property.

    #import "UIButton+Property.h"
    #import <algorithm>
    #import <vector>
    
    typedef std::pair<__weak id, __strong id> EntryType;
    static std::vector<EntryType> myAR;
    
    @implementation UIButton(Property)
    
    -(void) setProperty:(id)property
    {
        for (int i=0; i < myAR.size(); ++i) {
            if (myAR[i].first == self) {
                myAR[i].second = property;
                return;
            }
        }
        myAR.push_back(EntryType(self, property));
    }
    
    -(id) property
    {
        /* To save space, periodically erase the dictionary entries for
         * UIButton objects that have been deallocated. You can skip this
         * part, and even use NSMutableDictionary instead of this C++
         * stuff, if you don't care about leaking memory all over the place.
         */
        size_t n = myAR.size();
        for (size_t i=0; i < n; ++i) {
            if (myAR[i].first == nil)
                myAR[i] = myAR[--n];
        }
        myAR.resize(n);
    
        /* Look up "self" in our dictionary. */
        for (size_t i=0; i < myAR.size(); ++i) {
            EntryType &entry = myAR[i];
            if (entry.first == self) {
                return entry.second;
            }
        }
        return nil;
    }
    
    @end
    

    See also: http://labs.vectorform.com/2011/07/objective-c-associated-objects/

    0 讨论(0)
  • 2021-01-13 01:13

    A sample code available on git! Click here!

    0 讨论(0)
提交回复
热议问题