[英]Selectors or Blocks for callbacks in an Objective-C library
我們正在Objective-C中開發一個自定義的EventEmitter靈感消息系統。 對於聽眾提供回調,我們是否需要塊或選擇器以及為什么?
作為開發人員,您更願意使用哪個第三方庫? 哪個最符合Apple的軌跡,指導方針和做法?
我們正在使用Objective-C開發一個全新的iOS SDK,其他第三方將使用它來將功能嵌入到他們的應用程序中。 SDK的很大一部分需要向偵聽器傳遞事件。
我知道在Objective-C中做回調有五種模式,其中三種不適合:
stopPropagation()
)。 其中兩個是競爭者:
這可能看起來像一個深奧的意見問題,但我覺得有一個客觀的“正確”的答案,我只是在Objective-C中缺乏經驗來確定。 如果這個問題有一個更好的StackExchange站點,請幫助我將其移動到那里。
我們選擇塊作為為事件處理程序指定回調的方法。 我們對此選擇感到非常滿意,並且不打算刪除基於塊的偵聽器支持。 它確實有兩個值得注意的缺點:內存管理和設計阻抗。
塊最容易在堆棧上使用。 通過將它們復制到堆上來創建長壽命塊會引入有趣的內存管理問題。
調用包含對象上的方法的塊會隱式地提升self
的引用計數。 假設你有一個類的name
屬性的setter,如果你在一個塊中調用name = @"foo"
,編譯器將其視為[self setName:@"foo"]
並保留self
以便它不會當塊仍在周圍時解除分配。
實現EventEmitter意味着擁有長期存在的塊。 為了防止隱性保留,發射器的用戶需要創建一個__block
參考self
塊,前外:
__block *YourClass this = self;
[emitter on:@"eventName" callBlock:...
[this setName:@"foo"];...
}];
這種方法唯一的問題是, this
被調用的處理之前,可能被釋放。 因此,用戶必須在取消分配時取消注冊其偵聽器。
經驗豐富的Objective-C開發人員希望使用熟悉的模式與庫進行交互。 代表是一種非常熟悉的模式,因此規范的開發人員希望使用它。
幸運的是,委托模式和基於塊的偵聽器不是互斥的。 雖然我們的發射器必須能夠處理來自許多地方的偵聽器(只有一個委托不起作用),但我們仍然可以公開一個接口,允許開發人員與發射器進行交互,就像它們的類是委托一樣。
我們還沒有實現這一點,但我們可能會根據用戶的請求。
我不再致力於產生這個問題的項目,我很高興地回到了我原生的JavaScript之鄉。
接管這個項目的智能開發人員正確地決定完全退出我們的基於塊的自定義EventEmitter。 即將發布的版本已切換到ReactiveCocoa 。
這使得它們比先前提供的EventEmitter庫具有更高級別的信令模式,並且允許它們比基於塊的事件處理程序或類級方法更好地封裝信號處理程序內的狀態。
就個人而言,我討厭使用代表。 由於Objective-C的結構如何,它真的使代碼混亂如果我必須創建一個單獨的對象/添加協議只是為了通知你的一個事件,我必須實現5/6。 出於這個原因,我更喜歡積木。
雖然他們(塊)確實有它們的缺點(ex內存管理可能很棘手)。 它們易於擴展,易於實現,並且在大多數情況下才有意義 。
雖然apple的設計結構可能使用sender-delegate方法,但這只是為了向后兼容。 最近的Apple API一直在使用塊(來自CoreData),因為它們是objective-c的未來。 雖然它們在使用時可能會使代碼混亂,但它也允許更簡單的“匿名代表”,這在目標C中是不可能的。
最后,它實際上歸結為:你是否願意放棄一些較舊的,更加過時的平台來換取使用塊與代表? 委托的一個主要優點是它可以保證在任何版本的objc-runtime中工作,而塊是該語言的最新版本。
就NSNotificationCenter
/ KVO
而言,它們既有用又有其目的,但作為代表,它們並不打算被使用。 也不能將結果發送回發件人,在某些情況下,這是至關重要的(例如, -webView:shouldLoadRequest:
)。
我認為正確的做法是實現兩者,將其用作客戶端,並看看哪種感覺最自然。 這兩種方法都有優勢,它實際上取決於上下文以及您希望如何使用SDK。
選擇器的主要優點是簡單的內存管理 - 只要客戶端正確注冊和取消注冊,就不必擔心內存泄漏。 使用塊,內存管理可能會變得復雜,具體取決於客戶端在塊內執行的操作。 單元測試回調方法也更容易。 塊當然可以寫成可測試的 ,但是從我看到的內容來看並不常見。
塊的主要優點是靈活性 - 客戶端可以輕松引用局部變量而無需使用ivars。
所以我認為這僅僅取決於用例 - 這樣的一般設計問題沒有“客觀正確答案”。
很棒的寫作!
在個人觀點中,來自編寫大量JavaScript的事件驅動編程比讓代表來回更清晰。
關於偵聽器的內存管理方面,我嘗試解決這個問題(大量來自Mike Ash的MAKVONotificationCenter ),調整了調用者和發射器的dealloc
實現( 如此處所示 ),以便以兩種方式安全地刪除偵聽器。
我不完全確定這種方法有多安全,但我們的想法是嘗試它直到它破裂。
關於圖書館的一件事是,您只能在某種程度上預期,如何使用它。 所以你需要提供一個盡可能簡單和開放的解決方案 - 並且對用戶來說很熟悉。
關於API設計的一些有用的想法: http : //mattgemmell.com/2012/05/24/api-design/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.