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
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/
A sample code available on git! Click here!