2012-10-16 14 views
4

在我的iOS應用程序之間的循環依賴我想定義把對方作爲參數兩塊類型:的iOS塊定義

typedef void (^BlockA)(BlockB b); 
typedef void (^BlockB)(BlockA a); 

這種失敗,並在第一類型定義「未知類型名BlockB彙編(使感)。

我有一種變通方法,它定義這樣的類型:

typedef void (^BlockA)(id); 
typedef void (^BlockB)(BlockA a); 

我再投回到BLOCKa中定義裏面的BlockB類型,但在類型安全爲代價。

我也看過沒有使用typedefs,但是這會導致擴展塊定義的無限嵌套。

我知道如何解決具有前向聲明的結構的循環依賴關係,但我無法看到如何使用塊來完成此操作。

如果沒有解決方案的循環依賴,是否有一種方法,我可以限制參數BlockA爲任何塊類型,而不是通用的id,這會給一定程度的類型安全。

+0

AFAIK塊類型不能被轉發聲明。 – 2012-10-16 16:20:45

回答

2

typedef未定義「真實」類型。它基本上就像一個宏,隨時隨地擴展。這就是爲什麼typedef s不能遞歸。

另一種方式去思考它,typedef s爲將沒有必要 - 你總是可以採取任何的代碼與typedef,根本與基礎型取代它的每一個發生(這是編譯器,當你編譯),它將始終工作並完全等效。想一想 - 如果沒有typedef,你會怎麼做?你不能。所以你不能用typedef做。

做到這一點的唯一方法是:使用id作爲參數類型來擦除類型,就像你在做的一樣;或者將塊封裝在「真實」類型中,如struct或類。但是,如果以後一種方式執行,則必須明確地將塊放入並從結構或類中提取塊,這會使代碼混淆。另外,struct是危險的,因爲struct是一個標量C類型,如果需要通過塊捕獲它,它不會自動記憶管理結構中的對象。至於類,定義一個包裝類是非常詳細的,並使用它爲此會導致爲它包裝的每個塊分配一個無關的虛擬對象。

在我看來,使用id就像你使用的是很好,是最乾淨的方式。但是,請記住,如果需要將該塊作爲id由另一個內部塊捕獲,則應在捕獲之前將其重新轉換爲塊類型,因爲捕獲語義對於塊和其他對象類型是不同的塊被複制,而其他對象被保留)。只需在最早的地方將其重新轉換爲塊類型即可。

+0

感謝您的詳細解釋和確認方法,作爲一名新成員,我似乎無法爲您的答案投票。 – user1750593