2012-11-19 61 views
1

我來自.NET的Web應用程序背景,並剛剛開始iOS開發。我的應用程序的初始設計主要圍繞NSNotificationCenter。我對此非常滿意,直到我看到各種帖子解釋NSNotificationCentre是如何成爲常見的新手錯誤。這是NSNotificationCenter的有效用法

這裏有一個問題,我試圖解決的一個簡化版本:

我的應用程序試圖顯示了使用Web服務調用填充的郵件列表,認爲Facebook的消息。

當應用程序第一次加載時,它會從服務器中提取一組消息並將它們顯示在表中。用戶可以添加新消息(通過API發回),並且該應用可以接收關於添加到該消息的新消息的推送通知。

消息永遠不會保存到磁盤,所以我只是使用POCO模型來保持簡單。

我有一個MessageFeedController負責填充消息訂閱源視圖(在故事板中)。我還有一個消息提要模型,它存儲當前檢索的值並具有各種方法:

  • (void)loadFromServer;
  • (void)createMessage:(DCMMessage *)message;
  • (void)addMessage:(DCMMessage *)message;
  • (NSArray *)消息;
  • (int)unreadMessages;

當前實現我是這樣的:

用例1:初始加載

  1. 當視圖第一次出現的 「loadFromServer」 方法被調用。這填充消息集合並引發NSNotificationCenter事件。
  2. 控制器觀察到這個事件,並獲得當它填充的tableview

使用案例2:新郵件

  1. 當用戶點擊「添加」按鈕,將出現一個新的觀點,他們進入他們的消息,點擊發送,然後視圖被駁回。
  2. 這需要在模型上的CreateMessage方法,一旦我們有了模型引發NSNotificationCenter事件
  3. 再次MessageFeedController偵聽此事件,並重新填充表的響應,其調用API
接收Push消息

  1. 一個推送通知,而應用程序是開放的,與新的消息詳情
  2. 使用案例

  3. 的AppDelegate中(或其他類)將調用方法addMessage方法的模型,它
  4. 再次添加到集合中,假設MessageFeed觀點是開放的,它重新填充

在所有MessageFeed視圖被更新的三種情況。除此之外,BadgeManager還監聽這些事件,這些事件負責設置應用程序圖標徽章和標籤欄徽章,在這兩種情況下,徽章號碼都與未讀郵件的數量有關。

也有可能另一個視圖處於打開狀態並正在偵聽這些事件,此視圖包含消息摘要,因此需要知道集合何時更改。

對,感謝您堅持與我,我的問題是:這似乎是NSNotificationCentre的有效使用,還是我誤用了它?

我擔心的一個問題是,如果通過重新填充消息表,消息集合發生變化,我將不會100%確定會發生什麼情況。我唯一能看到這種情況的是如果收到關於新消息的推送通知。在這種情況下,無論如何,表格中的人員必須在完成NSNotification之前完成?

感謝您的幫助

丹。

+0

沒有試圖給出真正的答案,我會根據我見過的代碼評論「濫用」。兩種主要的O-C對象之間的解耦通信方法是委託協議和通知。第一個意思是某個對象將輔助函數實現爲另一個對象的服務;它的存在是已知的並且明確地使用。第二種模型是一個較弱的關係,其中一個對象聲明一個事件,零個,一個或多個對象決定採取行動。人們有時會造成這些屬性和需求的不匹配。 –

回答

3

換句話說,每當消息列表更新時就發佈通知。這是NSNotificationCenter的完美使用。

另一種選擇是使用Key-Value Observing

您的控制器(和任何其他人)可以註冊爲「消息」屬性的觀察者,並且只要該屬性發生更改就會通知您。在模型方面,您可以免費獲得KVO;只需調用名爲setMessages:的方法將觸發KVO更改通知。您還可以手動觸發通知,並且如果需要,KVO通知可以包括添加,刪除或更改陣列的哪些索引。

KVO是執行這些類型的更改通知的標準方式。使用實施OS X應用程序時,這一點尤其重要。

NSNotificationCenter更靈活,您可以將每個通知綁定任何其他信息。

重要的是要確保您的消息列表僅在主線程上更新,並且在未發佈相應更改通知的情況下從不修改消息列表。當控制器不是最頂層的視圖控制器或不在屏幕上時,您的控制器也應該注意忽略這些通知。在viewWillAppear:中註冊更改通知並取消註冊viewWillDisappear:的情況並不少見。

+0

嗨達倫,我想你比我說得簡潔得多! 我確實看過KVO,事實上這就是我開始的。但是我已經到了可以釋放對象但仍然有觀察者的地步,這會導致錯誤。發生這種情況是因爲Web服務有時會從提要中刪除消息。 我看到的帖子建議添加另一個可觀察的屬性(例如isAlive),當它爲false時,會告訴觀察者註銷自己。這只是感覺不太對,儘管也許這只是我。 –

+0

我是否也正確地說,只要數據發生變化(並重新載入表格)時通知控制器,那麼不應該有任何負載問題? –

+0

@DanRowlands這聽起來像是一個不同的問題。 KVO對象不需要知道關於觀察者的任何信息,也不必在取消分配前採取任何特殊行動。另一方面,觀察員必須在取消分配之前註銷自己,KVO和NSNotificationCenter都是如此。無論如何,在這種情況下,您將觀察模型的「消息」屬性,而不是單個消息對象。 – Darren

1

在我看來,使用委託協議模式會更適合這種情況。考慮在應用程序中的許多視圖控制器中使用「api層」需要的場景。如果將另一名開發人員引入您的代碼,他們將不得不尋找通知中心訂閱,而不是僅僅遵循一個乾淨的「接口」協議。

這就是說,你的代碼將工作得很好,這是通知中心的有效使用。這只是我個人偏好使用基於協議的方法的「更乾淨」的代碼。瀏覽iOS SDK本身,您將看到Apple自己使用協議並使用通知的情況。我覺得理解和使用這些協議要容易得多,而不是去挖掘並確定我必須傾聽的通知。

+0

嗨肖恩,這似乎是我讀過的一些博客上的流行觀點。你如何想象這可以與多個觀察者一起工作? –

+0

您是在問通知中心方法如何與多個觀察者或基於委託的方法一起工作? – shawnwall

+0

對不起,我的意思是,您的代表方式如何與多位觀察員合作 –

1

NSNotifications只要它們發佈,就會同步運行接收者代碼,因此在重新填充期間新消息將加入該執行隊列的後面。總的來說,它對我來說似乎是有效的,並且它保持視圖控制器和模型之間的合理程度的分離。

根據可能希望收聽相同信息的類的數量,您可能希望使用委託模式,也許保留委託對象的字典,但我個人不覺得這是可以很好地擴展,如果爲了避免崩潰而使用頁面,你還必須注意清理代表。總之,你的方法對我來說似乎很好。

+0

感謝您澄清執行順序。所以「重新填充」是作爲一個單獨的任務完成的,然後運行循環移動到通知(或下一步)?我應該花更多時間瞭解iOS中的運行循環。 –

+0

是的人口將在主線程上完成,並且通知代碼也會在主線程上運行。看起來最糟糕的是,如果兩個通知靠近在一起,表格會快速連續刷新兩次 –