objc_setAssociatedObject() et les amis ont été ajoutés à l'iPhone OS 3.1, donc si vous avez la possibilité de ciblage seulement 3.1+ périphériques vous pouvez en effet faire exactement la même chose que sur Snow Leopard ...
Si vous vous ne pouvez pas créer un dictionnaire statique des associations et des singes patch NSObjects méthode dealloc. Pour diverses raisons techniques, cette solution ne peut pas fonctionner correctement en présence de GC (ce qui explique pourquoi Apple a ajouté les trucs d'association), mais puisque l'iPhone ne supporte pas le GC, cela n'est pas un problème. Si vous venez de commencer à travailler sur ce projet, je recommande fortement d'utiliser les fonctions d'exécution et de cibler 3.1 plus, mais si ce n'est pas une option, voici un exemple de la façon dont vous le faites.
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, "[email protected]:");
}
}
@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
Oui, il est possible d'émuler l'extension ivars par catégorie sans aucune routine d'exécution supplémentaire. [Ici] (http://stackoverflow.com/questions/4887004/category-like-extension-for-instance-variables/4899521#4899521) est ma description comment. –