2013-07-29 75 views
1

我正在爲從python訪問目標c編寫lib,所以我使用Cython和目標c運行時訪問目標c。讓我們說用戶聲明這樣的屬性:從目標c運行時調用目標c @dynamic屬性的問題

@property (assign) NSString *prop_nsstring_dyn; 

而他希望使用@dynamic這個屬性。好吧,讓我們使用這個宏:

#define ADD_DYNAMIC_PROPERTY(PROPERTY_TYPE, PROPERTY_NAME, SETTER_NAME) \ 
\ 
@dynamic prop_nsstring_dyn; \ 
- (PROPERTY_TYPE) PROPERTY_NAME \ 
{ \ 
printf("returning\n"); \ 
return (PROPERTY_TYPE) objc_getAssociatedObject(self, @selector(PROPERTY_NAME)); \ 
} \ 
\ 
- (void) SETTER_NAME :(PROPERTY_TYPE) PROPERTY_NAME \ 
{ \ 
printf("setting\n"); \ 
objc_setAssociatedObject(self, @selector(PROPERTY_NAME), PROPERTY_NAME, OBJC_ASSOCIATION_RETAIN); \ 
} \ 

此之後,我們可以在@implementation稱之爲:

ADD_DYNAMIC_PROPERTY(NSString*, prop_nsstring_dyn, setProp_nsstring_dyn); 

如果我們從Objective C的呼籲是這樣的:

c.prop_nsstring_dyn = @"test str"; 

c.prop_nsstring_dyn; 

getters and setters are call正確編輯。 但是,我需要設置並從目標c運行時獲得這個動態屬性的值,所以如果我使用像objc_getIvar/objc_setIvar這樣的函數,getters和setters根本不會被調用,並且我得到空指針作爲結果。

有沒有人知道如何調用get/set funcs。來自客觀c運行時的動態屬性?

謝謝!

+1

你有調查pyobjc嗎? – bbum

+0

是的,我看着pyobjc源碼,他們有不同的方法比我,但我認爲@Nathan日的答案將幫助我 – user232343

+1

很酷;只是要確保你不是在重新發明特定的車輪。 :) – bbum

回答

2

您可以使用NSObject的方法

- [NSObject setValue:(id) forKey:(NSString *)]; 
- (id)[NSObject valueForKey:(NSString *)]; 

其中關鍵的是屬性名稱間接調用的setter和getter方法,如果屬性是靈長類動物的類型一樣無符號長,雙等,然後執行setValue值方法將處理NSNumber等價物。

您也可以致電酒店setter和getter調用其他方法以同樣的方式,所以你可以使用所有你可以用常規方法使用動態方法調用的功能,還以爲你可能已經工作了這一點。

+0

我不確定上述簽名是否正確 –

+0

有沒有什麼方法可以用objc運行時實際獲取某些屬性的getter和setter IMP? – user232343

+1

如果您不在某處實施它們,則不應該這樣做;如果方法不存在,KVC機制將回退到直接訪問。如果它們是直接實現的,通過綜合實現的,或者是在運行時生成的 - 那麼它們將像其他任何方法一樣運行。 – bbum

3

getters和setters被調用正確。但是,我需要設置並從目標c運行時獲得這個動態屬性的值,所以如果我使用像objc_getIvar/objc_setIvar這樣的函數,getters和setters根本不會被調用,並且我得到空指針作爲結果。

這是你的錯。您不應該撥打objc_getIvarobjc_setIvar與其他對象屬性進行交互。屬性不是ivars。屬性是實現方法的承諾。你不能假設這些方法是如何實現的。你當然不能認爲他們相當於打電話給objc_getIvar(正如你發現的那樣)。

@ NathanDay的方法,使用KVC,是一個體面的方法,但[obj valueForKey:@"foo"]是不完全相同的事情[obj foo]。儘管如此,它很接近。

首先,要清楚的是,您並不真正「獲得對象屬性的價值」。你甚至不用「調用對象方法」。您將消息發送給對象並返回結果。屬性通常是一種方便的方式來聲明您將響應某些消息(選擇器)。

要正確發送消息,您必須致電objc_msgSend。請注意,它有幾種形式,具體取決於返回值是浮點還是結構(這是關於使用valueForKey:的好處;它使所有返回值看起來相同,並且不需要知道哪個表單請致電objc_msgSend)。無論如何,您需要知道如何解釋返回值,因爲它可能是id或者它可能是標量。

我不相信有可能在最常見的情況下(例如,如果類實現forwardingTargetForSelector:)在運行時確定選擇器的返回類型。你真的應該在編譯時從頭文件中獲取這些信息。但在大多數情況下,您可以在運行時使用class_getPropertyproperty_getAttributesclass_getInstanceMethodmethod_getReturnType(您需要同時檢查;開發人員必須聲明「屬性類似的東西」的規則與@property)確定返回值。

雖然有可能獲得實際的C函數指針來實現一個方法,但您通常不應該從對象之外執行此操作。 ObjC對象處理消息的方法有很多,不會轉換爲「使用該名稱調用方法」。你應該傳遞消息並讓對象自己處理事情。

但是對於閱讀和書寫屬性,Nathan的KVC方法可能是您所需要的。不過,我真的建議你再看看PyObjC,因爲他們已經解決了這些問題。至少,我會非常仔細地研究他們的代碼。

+0

我解決了Nathan的KVC方法的問題,它現在正在工作:) – user232343