更新:
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