2009-09-10 10 views
6

अद्यतन में "नकली" ivars करने के लिए:कैसे एक Obj सी श्रेणी (iPhone)

iPhone OS 3.1 संबंधित किया जाता है वस्तुओं। हालांकि, आईफोन सिम्युलेटर नहीं करता है। यदि आप सिम्युलेटर में संबंधित ऑब्जेक्ट कोड का परीक्षण करना चाहते हैं, तो आपको एक बग फाइल करना चाहिए।

मेरा SO प्रश्न here देखें।

rdar: // 7477326


Snow Leopard अब संबंधित किया जाता है वस्तुओं।

क्या संबंधित वस्तुओं के बिना कुछ पूरा करने का कोई तरीका है? (विशेष रूप से आईफोन के लिए।)

मुझे पूरा यकीन है कि मैंने कुछ समय पहले ऐसा कुछ देखा था, लेकिन मुझे याद नहीं है। किसी ऑब्जेक्ट को केवीसी कंटेनर में बदलने के बारे में कुछ।

+0

हां, किसी भी अतिरिक्त रन-टाइम दिनचर्या के बिना श्रेणी के माध्यम से इवर एक्सटेंशन का अनुकरण करना संभव है। [यहां] (http://stackoverflow.com/questions/4887004/category-like-extension-for-instance-variables/4899521#4899521) मेरा वर्णन कैसे है। –

उत्तर

13

objc_setAssociatedObject() और दोस्तों के iPhone OS 3.1 में जोड़ा गया था, ताकि आप वास्तव में हिमपात तेंदुए पर के रूप में सटीक एक ही बात कर सकते हैं अगर आप सिर्फ 3.1+ उपकरणों लक्ष्यीकरण का विकल्प होता है ...

आप तो क्या आप NSObjects dealloc विधि से एसोसिएशन और बंदर पैच का स्थिर शब्दकोश नहीं बना सकते हैं। विभिन्न तकनीकी कारणों से इस समाधान जीसी की उपस्थिति (जिसके कारण सेब संघ सामान जोड़ा) में सही ढंग से काम करने के लिए नहीं किया जा सकता है, लेकिन iPhone जीसी है कि एक गैर मुद्दा है का समर्थन नहीं करता क्योंकि।

तुम सिर्फ इस परियोजना मैं अत्यधिक क्रम कार्यों का उपयोग करने और लक्षित कर 3.1 प्लस की सिफारिश पर काम शुरू कर रहे हैं, लेकिन यह है कि अगर नहीं है यहाँ एक विकल्प तुम कैसे करते का एक उदाहरण है।

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 
+0

धन्यवाद, मेरे रिलीज नोट्स पढ़ना चाहिए था। NSObject के डेलोक कार्यान्वयन को स्वैप करना निश्चित रूप से आपको कहीं से प्रतिबंधित कर सकता है। –

3

आप उन्हें हमेशा एक सिंगलटन में संग्रहीत कर सकते थे।

2

एक सामान्य श्रेणी में ऐसा करने के कोई अच्छे तरीके नहीं हैं।

आप आसानी से एक वैश्विक NSMutableDictionary कि जो कुछ भी डेटा आप चाहते हैं के लिए किसी भी मनमाने ढंग से NSObject से नक्शे होने से एक वस्तु के लिए डेटा जोड़ सकते हैं। समस्या यह है कि ऑब्जेक्ट को कब हटाया जाता है, यह जानने का कोई तरीका नहीं है, इसलिए जब डेटा खराब हो जाता है तो आप (सामान्य रूप से) नहीं बता सकते हैं।

इस हल करने के लिए केवल सामान्य तरीके से विधि swizzling उपयोग करने के लिए वस्तु का आवंटन रद्द करने की रिपोर्ट और अपने संबद्ध डेटा को रिहा करने NSObject dealloc विधि को बदलने के लिए है। मुझे यकीन है कि किसी ने यह किया है, लेकिन इस तरह के एक भयानक हैक एक मान्य appropach के रूप में सिफारिश करने के लिए बहुत मुश्किल होगा।

अब, यदि प्रश्नों में आपकी ऑब्जेक्ट्स में जीवन चक्र की निगरानी करने के लिए कोई अन्य तरीका है (यानी, कुछ डीलोकेशन हुक, किसी प्रतिनिधि ऑब्जेक्ट की तरह किसी ऑब्जेक्ट ऑब्जेक्टब्लिल विधि), तो आप उसमें अपने संबंधित डेटा को रिलीज़ करने के लिए इसमें शामिल हो सकते हैं और तकनीक को सीधे आगे और वैध बना देगा।

+0

आईफोन में स्पष्ट रूप से जीसी नहीं है, लेकिन इसके बजाय कमजोर कुंजियों के साथ एनएसएमएपीटेबल का उपयोग करना संभव नहीं होगा? http://developer.apple.com/documentation/Cocoa/Reference/NSMapTable_class/ –

+0

आप वास्तव में ऐसा नहीं कर सकते क्योंकि आम तौर पर उस तालिका में कुंजी सक्रिय वस्तु को रूट करने वाली एकमात्र चीज है, इसलिए यदि यह कमजोर है तो यह होगा तुरंत इसे GCed होने के लिए योग्य बनें और इसे सेट करने के बाद शून्य हो जाएं जब यह सीधे स्टैक के माध्यम से रूट न हो जाए। –

0

मैं एक जवाब जोड़ देंगे।

मैं मूल blog post पाया, यह स्टीव Degutis से था।

इसमें मूल रूप से valueForUndefinedKey:, setValue:ForUndefinedKey:, और dealloc के लिए NSObject के तरीकों को प्रतिस्थापित करना शामिल है। फिर किसी भी अपरिभाषित कुंजी को स्टोर करने के लिए एक स्थिर शब्दकोश का उपयोग करना।

लुइस के समाधान के रूप में बस इतना बुरा और मजेदार है।

0

समवर्ती मुद्दों के लिए चिंताओं के बावजूद, वैश्विक चर का उपयोग क्यों न करें? यहां तक ​​कि रनटाइम objc_set/एसोसिएटेड ऑब्जेक्ट() विधियों का उपयोग करने से आप एक "वैश्विक" स्थैतिक चर पता नहीं पारित कर रहे हैं, जिस स्थिति में आपके पास अभी भी समेकन समस्याएं हैं?

संबंधित मुद्दे