更新:
iPhone OS 3.1具有关联的对象.但是,iPhone模拟器没有.如果要在模拟器中测试关联对象代码,则应该提交错误.
看我的问题here.
rdar:// 7477326
Snow Leopard现在有相关的对象.
有没有办法在没有相关对象的情况下完成类似的事情? (专门针对iPhone.)
我很确定我曾经看过这样的事情,但我不记得在哪里.关于将任何对象转换为KVC容器的事情.
解决方法
objc_setAssociatedObject()和朋友被添加到iPhone OS 3.1中,所以如果您可以选择仅定位3.1设备,那么您实际上可以执行与Snow Leopard完全相同的操作……
如果你不能,你可以创建一个静态的关联字典和猴子补丁NSObjects dealloc方法.由于各种技术原因,这种解决方案无法在GC存在的情况下正常工作(这就是苹果添加关联内容的原因),但由于iPhone不支持GC,因此不存在问题.
如果你刚刚开始研究这个项目,我强烈建议你使用运行时函数并定位3.1 plus,但如果这不是一个选项,那么这里就是你如何做的一个例子.
LGAssociativeStorage.h:
#import <pthread.h> #import <Foundation/Foundation.h> @interface NSObject (LGAssociativeStorage) @property (retain) id associatedObject; @end
LGAssociativeStorage.mm
#import <objc/runtime.h> #import "LGAssociativeStorage.h" /* We are using STL containers because: 1) Using Objective C containers can cause deallocs which cause recursion issues 2) STL containers are high perf containers that don't introduce external code dependencies Ideally one could include a thread safe map implementation,but I don't need one currently */ #include <map> typedef std::map<id,id> idMap_t; typedef std::pair<id,id> idPair_t; static NSMutableDictionary * data = nil; static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER; static IMP gOriginalNSObjectDealloc = nil; static idMap_t associatedObjectMap; static void removeAssociatedObjectFromMap(id self) { idMap_t::iterator iter = associatedObjectMap.find(self); if( iter != associatedObjectMap.end() ) { [iter->second release]; associatedObjectMap.erase(iter); } } static id newNSObjectDealloc(id self,SEL deallocSelector,...) { pthread_mutex_lock(&data_lock); removeAssociatedObjectFromMap(self); pthread_mutex_unlock(&data_lock); return gOriginalNSObjectDealloc(self,deallocSelector); } static void initIfNecessary(void) { if (!data) { data = [[NSMutableDictionary alloc] init]; // The below line of code is abusive... in the future the Objective C runtime will use it as evidence // that I am an unfit software engineer and take custody of all my code gOriginalNSObjectDealloc = class_replaceMethod([NSObject class],@selector(dealloc),newNSObjectDealloc,"v@:"); } } @implementation NSObject (LGAssociativeStorage) - (id) associatedObject { id retval = nil; pthread_mutex_lock(&data_lock); initIfNecessary(); idMap_t::iterator iter = associatedObjectMap.find(self); if( iter != associatedObjectMap.end() ) { retval = iter->second; } pthread_mutex_unlock(&data_lock); return retval; } - (void) setAssociatedObject:(id)object_ { pthread_mutex_lock(&data_lock); initIfNecessary(); removeAssociatedObjectFromMap(self); [object_ retain]; associatedObjectMap.insert(idPair_t(self,object_)); pthread_mutex_unlock(&data_lock); } @end