<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                在觀察者模式里,一個對象在狀態變化的時候會通知另一個對象。參與者并不需要知道其他對象的具體是干什么的 - 這是一種降低耦合度的設計。這個設計模式常用于在某個屬性改變的時候通知關注該屬性的對象。 常見的使用方法是觀察者注冊監聽,然后再狀態改變的時候,所有觀察者們都會收到通知。 在 MVC 里,觀察者模式意味著需要允許?`Model`?對象和?`View`?對象進行交流,而不能有直接的關聯。 `Cocoa`?使用兩種方式實現了觀察者模式:?`Notification`?和?`Key-Value Observing (KVO)`。 ### 通知 - Notification 不要把這里的通知和推送通知或者本地通知搞混了,這里的通知是基于訂閱-發布模型的,即一個對象 (發布者) 向其他對象 (訂閱者) 發送消息。發布者永遠不需要知道訂閱者的任何數據。 `Apple`?對于通知的使用很頻繁,比如當鍵盤彈出或者收起的時候,系統會分別發送`UIKeyboardWillShowNotification/UIKeyboardWillHideNotification`?的通知。當你的應用切到后臺的時候,又會發送?`UIApplicationDidEnterBackgroundNotification`?的通知。 注意:打開?`UIApplication.swift`?文件,在文件結尾你會看到二十多種系統發送的通知。 #### 如何使用通知 打開?`AlbumView.swift`?然后在?`init`?的最后插入如下代碼: ~~~ NSNotificationCenter.defaultCenter().postNotificationName("BLDownloadImageNotification", object: self, userInfo: ["imageView":coverImage, "coverUrl" : albumCover]) ~~~ 這行代碼通過?`NSNotificationCenter`?發送了一個通知,通知信息包含了?`UIImageView`?和圖片的下載地址。這是下載圖像需要的所有數據。 然后在?`LibraryAPI.swift`?的?`init`?方法的?`super.init()`?后面加上如下代碼: ~~~ NSNotificationCenter.defaultCenter().addObserver(self, selector:"downloadImage:", name: "BLDownloadImageNotification", object: nil) ~~~ 這是等號的另一邊:觀察者。每當?`AlbumView`?發出一個?`BLDownloadImageNotification`?通知的時候,由于?`LibraryAPI`?已經注冊了成為觀察者,所以系統會調用?`downloadImage()`?方法。 但是,在實現?`downloadImage()`?之前,我們必須先在?`dealloc`?里取消監聽。如果沒有取消監聽消息,消息會發送給一個已經銷毀的對象,導致程序崩潰。 在?`LibaratyAPI.swift`?里加上取消訂閱的代碼: ~~~ deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } ~~~ 當對象銷毀的時候,把它從所有消息的訂閱列表里去除。 這里還要做一件事情:我們最好把圖片存儲到本地,這樣可以避免一次又一次下載相同的封面。 打開?`PersistencyManager.swift`?添加如下代碼: ~~~ func saveImage(image: UIImage, filename: String) { let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)") let data = UIImagePNGRepresentation(image) data.writeToFile(path, atomically: true) } func getImage(filename: String) -> UIImage? { var error: NSError? let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)") let data = NSData(contentsOfFile: path, options: .UncachedRead, error: &error) if let unwrappedError = error { return nil } else { return UIImage(data: data!) } } ~~~ 代碼很簡單直接,下載的圖片會存儲在?`Documents`?目錄下,如果沒有檢查到緩存文件,`getImage()`?方法則會返回?`nil`?。 然后在?`LibraryAPI.swift`?添加如下代碼: ~~~ func downloadImage(notification: NSNotification) { //1 let userInfo = notification.userInfo as [String: AnyObject] var imageView = userInfo["imageView"] as UIImageView? let coverUrl = userInfo["coverUrl"] as NSString //2 if let imageViewUnWrapped = imageView { imageViewUnWrapped.image = persistencyManager.getImage(coverUrl.lastPathComponent) if imageViewUnWrapped.image == nil { //3 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in let downloadedImage = self.httpClient.downloadImage(coverUrl) //4 dispatch_sync(dispatch_get_main_queue(), { () -> Void in imageViewUnWrapped.image = downloadedImage self.persistencyManager.saveImage(downloadedImage, filename: coverUrl.lastPathComponent) }) }) } } } ~~~ 拆解一下上面的代碼: * `downloadImage`?通過通知調用,所以這個方法的參數就是?`NSNotification`?本身。`UIImageView`?和?`URL`?都可以從其中獲取到。 * 如果以前下載過,從?`PersistencyManager`?里獲取緩存。 * 如果圖片沒有緩存,則通過?`HTTPClient`?獲取。 * 如果下載完成,展示圖片并用?`PersistencyManager`?存儲到本地。 再回顧一下,我們使用外觀模式隱藏了下載圖片的復雜程度。通知的發送者并不在乎圖片是如何從網上下載到本地的。 運行一下項目,可以看到專輯封面已經顯示出來了: [![](http://cdn1.raywenderlich.com/wp-content/uploads/2014/11/swiftDesignPattern13-288x320.png)](http://cdn1.raywenderlich.com/wp-content/uploads/2014/11/swiftDesignPattern13-288x320.png) 關了應用再重新運行,注意這次沒有任何延時就顯示了所有的圖片,因為我們已經有了本地緩存。我們甚至可以在沒有網絡的情況下正常使用我們的應用。不過出了問題:這個用來提示加載網絡請求的小菊花怎么一直在顯示! 我們在下載圖片的時候開啟了這個白色小菊花,但是在圖片下載完畢的時候我們并沒有停掉它。我們可以在每次下載成功的時候發送一個通知,但是我們不這樣做,這次我們來用用另一個觀察者模式: KVO 。 ### 鍵值觀察 - KVO 在 KVO 里,對象可以注冊監聽任何屬性的變化,不管它是否持有。如果感興趣的話,可以讀一讀[蘋果 KVO 編程指南](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html)。 #### 如何使用 KVO 正如前面所提及的, 對象可以關注任何屬性的變化。在我們的例子里,我們可以用 KVO 關注`UIImageView`?的?`image`?屬性變化。 打開?`AlbumView.swift`?文件,找到?`init(frame:albumCover:)`?方法,在把?`coverImage`?添加到?`subView`?的代碼后面添加如下代碼: ~~~ coverImage.addObserver(self, forKeyPath: "image", options: nil, context: nil) ~~~ 這行代碼把?`self`?(也就是當前類) 添加到了?`coverImage`?的?`image`?屬性的觀察者里。 在銷毀的時候,我們也需要取消觀察。還是在?`AlbumView.swift`?文件里,添加如下代碼: ~~~ deinit { coverImage.removeObserver(self, forKeyPath: "image") } ~~~ 最終添加如下方法: ~~~ override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) { if keyPath == "image" { indicator.stopAnimating() } } ~~~ 必須在所有的觀察者里實現上面的代碼。在檢測到屬性變化的時候,系統會自動調用這個方法。在上面的代碼里,我們在圖片加載完成的時候把那個提示加載的小菊花去掉了。 再次運行項目,你會發現一切正常了: [![](http://cdn3.raywenderlich.com/wp-content/uploads/2014/11/swiftDesignPattern14-292x320.png)](http://cdn3.raywenderlich.com/wp-content/uploads/2014/11/swiftDesignPattern14-292x320.png) 注意:一定要記得移除觀察者,否則如果對象已經銷毀了還給它發送消息會導致應用崩潰。 此時你可以把玩一下當前的應用然后再關掉它,你會發現你的應用的狀態并沒有存儲下來。最后看見的專輯并不會再下次打開應用的時候出現。 為了解決這個問題,我們可以使用下一種模式:備忘錄模式。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看