2010-07-13 56 views
5

我在Objective-C中編寫了一個宏來執行安全的投射。這裏是什麼樣子至今:Objective-C安全鑄造宏

#define SAFE_CAST(OBJECT, TYPE) ([OBJECT isKindOfClass:[TYPE class]] ? (TYPE *) OBJECT: nil) 

這個作品真的很好,但它會是很好,如果有存儲對象的變量,因此沒有被調用兩次的方式。例如,使用宏這樣:

NSString *str = SAFE_CAST([dictinary objectForKey:key], NSString); 

結果類似下面的代碼,當宏展開:

NSString *str = ([[dictinary objectForKey:key] isKindOfClass:[NSString class]] ? (NSString *) [dictinary objectForKey:key]: nil); 

我寧願爲它更像是這方面的工作:

id obj = [dictionary objectForKey:key]; 
NSString *str = ([obj objectForKey:key] isKindOfClass[NSString class]] ? (NSString *) obj : nil); 

謝謝。

+0

我沒有看到這點是什麼。你曾經說過你想用它來清理plists,但是如果你使用這個,你必須測試返回的對象是否爲零?爲什麼不測試對象是否爲KindOfClass:expectedClass? – JeremyP 2010-07-13 08:05:05

回答

8

您可以使用GCC擴展名爲聲明statement expressions

#define SAFE_CAST(OBJECT, TYPE) ({ id obj=OBJECT;[obj isKindOfClass:[TYPE class]] ? (TYPE *) obj: nil; }) 

這麼說,我覺得它通常是一個不錯的辦法有,你需要使用SAFE_CAST很多的情況。 永遠不要將不同類的對象放在數組中;不要爲不同類的UI對象重複使用動作消息(IBAction)someAction:(id)sender。那麼你通常不需要使用SAFE_CAST

+1

現在我正在使用這個宏來讀取plist中的信息。我不能保證plist的內容是有效的。就像其他演員一樣;它可以被濫用,但它有其用途。如果有更好的方法可以做到這一點,請您詳細說明一下嗎?根據您的回覆,語句表達式看起來很有趣。它們可以與LLVM一起使用嗎? – LandonSchropp 2010-07-13 04:03:19

+0

是的,它與'clang'一起使用。至於'plist',我同意使用'SAFE_CAST',如果它是用戶提供的。但如果不是這樣,我認爲在開發過程中最好使用'NSAssert',這樣當我準備一個無效的plist時程序崩潰了;你的應用程序的發佈版本不需要'SAFE_CAST',因爲你確定'plist'是有效的。 – Yuji 2010-07-13 04:28:30

+0

工程很棒。謝謝。 – LandonSchropp 2010-07-18 01:01:04

0

所以就這樣寫下來,把它包裝在do {} while(0)< - 而不僅僅是括號中。

#define SAFE_CAST(OBJECT, TYPE, VAR) do { \ 
    id obj = OBJECT; \ 
    VAR = [obj isKindOfClass:[TYPE class]] ? (TYPE *) obj : nil; \ 
} while(0) 
+0

我不能在上面使用的用法中正確地編譯它。編譯器輸出:error:'do'之前的預期表達式。 – LandonSchropp 2010-07-13 02:41:24

+0

呃你說得對,對不起。首先在nil後缺少語法錯誤,其次,它需要自立。意思是要麼傳遞另一個指定三元操作輸出的參數,要麼以另一種方式進行。 :) – jer 2010-07-13 02:52:58

+0

不用擔心。無論如何感謝您的答覆。 – LandonSchropp 2010-07-13 04:28:33

4

如果你真的認爲你必須這樣做,你可以使用一個函數:

#define SAFE_CAST(Object, Type) (Type *)cast_helper(Object, [Type class]) 
static id cast_helper(id x, Class c) { 
    return [x isKindOfClass:c] ? x : nil; 
} 
+0

這是一個有趣的方法,但一個宏只是看起來更清潔。我試圖避免讓全局函數浮動。另外,你能否詳細說明你的意思是「如果你真的認爲你必須這樣做」?其他幾種語言支持安全轉換,包括C#和C++。爲什麼我不應該使用它們? – LandonSchropp 2010-07-13 04:12:16

+1

@ helixed:你爲什麼認爲掛在身邊的全球宏比任何一個懸而未決的全球功能都好? – JeremyP 2010-07-13 08:02:28

+0

@helixed:對於上面提到的plist方法來說,它恰好適用於那些真正需要動態演員陣容的情況。儘管我沒有看到全局函數的具體問題,但我寧願使用函數,而不使用只執行直接文本處理的宏。 – 2010-07-13 13:41:04