2009-12-16 3 views
8

Dans le 3.1 SDK, Apple a ajouté la prise en charge des objets associés. Cependant, le simulateur ne compilera pas le code qui inclut des références à objc_setAssociatedObject, objc_getAssociatedObject, et al. (Erreurs non déclarées)objc_setAssociatedObject indisponible dans le simulateur iPhone

Y a-t-il des alentours? Puis-je faire que le simulateur iPhone compile ce code? Je détesterais avoir à faire tous les tests sur l'appareil.


Mise à jour

Bug Filed: rdar: // 7477326

+1

Utilisez-vous 10.5 ou 10.6 pour le développement? –

+0

10.6, Installation fraîche –

+2

Envoyez un bogue via http://bugreport.apple.com/ et modifiez votre question pour inclure le #, s'il vous plaît. – bbum

Répondre

1

Une solution rapide et sale (en grande partie non testé, peut être bogué):

#if TARGET_IPHONE_SIMULATOR 

#import <objc/runtime.h> 

enum { 
    OBJC_ASSOCIATION_ASSIGN = 0, 
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, 
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3, 
    OBJC_ASSOCIATION_RETAIN = 01401, 
    OBJC_ASSOCIATION_COPY = 01403 
}; 
typedef uintptr_t objc_AssociationPolicy; 

@implementation NSObject (OTAssociatedObjectsSimulator) 

static CFMutableDictionaryRef theDictionaries = nil; 

static void Swizzle(Class c, SEL orig, SEL new) // swizzling by Mike Ash 
{ 
    Method origMethod = class_getInstanceMethod(c, orig); 
    Method newMethod = class_getInstanceMethod(c, new); 
    if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) 
     class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 
    else 
     method_exchangeImplementations(origMethod, newMethod); 
} 

- (NSMutableDictionary *)otAssociatedObjectsDictionary 
{ 
    if (!theDictionaries) 
    { 
     theDictionaries = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); 
     Swizzle([NSObject class], @selector(dealloc), @selector(otAssociatedObjectSimulatorDealloc)); 
    } 

    NSMutableDictionary *dictionary = (id)CFDictionaryGetValue(theDictionaries, self); 
    if (!dictionary) 
    { 
     dictionary = [NSMutableDictionary dictionary]; 
     CFDictionaryAddValue(theDictionaries, self, dictionary); 
    } 

    return dictionary; 
} 

- (void)otAssociatedObjectSimulatorDealloc 
{ 
    CFDictionaryRemoveValue(theDictionaries, self); 
    [self otAssociatedObjectSimulatorDealloc]; 
} 

@end 

void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) 
{ 
    NSCAssert(policy == OBJC_ASSOCIATION_RETAIN_NONATOMIC, @"Only OBJC_ASSOCIATION_RETAIN_NONATOMIC supported"); 

    [[object otAssociatedObjectsDictionary] setObject:value forKey:[NSValue valueWithPointer:key]]; 
} 

id objc_getAssociatedObject(id object, void *key) 
{ 
    return [[object otAssociatedObjectsDictionary] objectForKey:[NSValue valueWithPointer:key]]; 
} 

void objc_removeAssociatedObjects(id object) 
{ 
    [[object otAssociatedObjectsDictionary] removeAllObjects]; 
} 

#endif 
3

Je don Je pense que cela sera corrigé dans les SDK 3.x, donc une autre solution est de simplement définir les fonctions et appeler jusqu'à la prochaine définition vi une recherche dynamique.

tête:

#if TARGET_IPHONE_SIMULATOR 
enum { 
    OBJC_ASSOCIATION_ASSIGN = 0, 
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, 
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3, 
    OBJC_ASSOCIATION_RETAIN = 01401, 
    OBJC_ASSOCIATION_COPY = 01403 
}; 
typedef uintptr_t objc_AssociationPolicy; 

void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy); 
id objc_getAssociatedObject(id object, void *key); 
void objc_removeAssociatedObjects(id object); 
#endif 

Mise en œuvre:

#if TARGET_IPHONE_SIMULATOR 
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) { 
    ((void (*)(id, void *, id, objc_AssociationPolicy)) 
    dlsym(RTLD_NEXT, "objc_setAssociatedObject")) (object, key, value, policy); 
} 
id objc_getAssociatedObject(id object, void *key) { 
    return ((id (*)(id, void *)) 
      dlsym(RTLD_NEXT, "objc_getAssociatedObject"))(object, key); 
} 
void objc_removeAssociatedObjects(id object) { 
    ((void (*)(id)) 
    dlsym(RTLD_NEXT, "objc_removeAssociatedObjects"))(object); 
} 
#endif 
+0

Merci! J'ai aussi dû ajouter #define _GNU_SOUCE pour résoudre RTLD_NEXT. –

Questions connexes