你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 詳解Objective-C設計模式編程中對備忘錄模式的運用

詳解Objective-C設計模式編程中對備忘錄模式的運用

編輯:IOS開發綜合

基本理解
這個模式有三個關鍵角色:原發器(Originator)、備忘錄(Memento)、看管人(caretaker)。三者的基本關系是:原發器創建一個包含其狀態的備忘錄,並傳給看管人。看管人不知道如何與備忘錄交互,但會把備忘錄放在一個安全之處保管好。
備忘錄(Memento):在 不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可以將該對象回復到原先保存的狀態。
Originator(發起人):負責創建一個備忘錄,用以記錄當前時刻它的內部狀態,並且可使用恢復備忘錄內部狀態。Originator可根據需要決定Memento存儲Originator的哪些內部狀態。
Memento(備忘錄):負責存儲Originator對象的內部狀態,並可防止Originator以外的其他對象訪問備忘錄。備忘錄有兩個接口,CareTaker
只能看到備忘錄的窄接口,它只能將備忘錄傳給其他對象。originator能夠看到一個寬接口,允許它訪問返回到先前狀態所需的所有數據。
Caretaker(管理者):負責保存好備忘錄,不能對備忘錄的內容進行操作或檢查。
就是把要保存的細節給封裝在了Memento中,哪一天要更改保存的細節也不用影響客戶端了。

備忘錄使用場合
備忘錄模式比較適用於功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一小部分時,Orignator可以根據保存的Memento信息還原到前一狀態。
如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那麼命令模式可以使用備忘錄模式來存儲撤銷操作的狀態。有的時候一些對象的內部信息必須要保存在對象以外的地方,但是必須要由對象自己讀取,這時,使用備忘錄可以把復雜的對象內部信息對其他的對象屏蔽起來。
用於獲取狀態的接口會暴露實現接口,需要將其屏蔽起來。
它一般應用於游戲、文字處理程序的設計中,這種程序需要保存當前上下文的復雜狀態的快照並在以後恢復處理。

作用
當角色的狀態改變時,有可能這個狀態無效,這時候就可以使用暫時存儲起來的備忘錄將狀態復原。
Cocoa Touch框架中的備忘錄模式
Cocoa Touch框架在歸檔、屬性列表序列化和核心數據采用了備忘錄模式。
Cocoa的歸檔是對對象以及其屬性還有同其他對象間的關系進行編碼,形成一個文檔,該文檔既可保存與文件系統中,也可在進程或網絡間傳送。對象與其他對象的關系被看做對象圖的網絡。
歸檔過程把對象保存為一種與架構無關的字節流,保持對象的標識以及對象之間的關系。對象的類型也同數據一起保存。從字節流解碼出來的對象通常用於對象編碼時相同的類進行實例化。使用NSCoder的具體類NSKeyedArchiver和NSKeyedUnarchiver,使用基於鍵的歸檔技術,被編碼與解碼的對象必須遵守NSCoding協議並實現以下方法:

復制代碼 代碼如下:
-(id)initWithCoder:(NSCoder *)coder;
-(void)encodeWithCoder:(NSCoder *)coder;

實例
添加下面兩個方法到 ViewController.m 文件:
復制代碼 代碼如下:
- (void)saveCurrentState
{
    // 當用戶退出應用之後再重新打開,他想要跟他之前退出時一樣的狀態
    // 退出應用,這個時候我們需要做的是把當前顯示的專輯存儲下來
    // 因為只有一小片信息,我們可用 NSUserDefaults 來存儲信息
    [[NSUserDefaults standardUserDefaults] setInteger:currentAlbumIndex forKey:@“currentAlbumIndex”];
}

- (void)loadPreviousState
{
    currentAlbumIndex = [[NSUserDefaults standardUserDefaults] integerForKey@“currentAlbumIndex”];
    [self showDataForAlbumAtIndex:currentAlbumIndex];
}

saveCurrentState 存儲當前專輯的索引到 NSUserDefaults ─ NSUserDefaults 是一個標准數據存儲,iOS 用來專門存放程序設置和數據。

loadPreviousState 加載這之前存儲的專輯索引。這不是備忘錄模式的全部,不過你已經達到目的了。

現在,在 ViewController.m 裡,滾動視圖初始化之前,在 viewDidLoad 裡添加下面一行:
復制代碼 代碼如下:
[self loadPreviousState];

當程序啟動的時候加載上一次存儲的狀態。但是你在哪裡存儲程序的當前狀態呢?你需要使用通知來做這樣的事情。當程序進入後台時,iOS 會發送一個 UIApplicationDidEnterBackgroundNotification 通知。你可利用這個通知調用 saveCurrentState。就這麼方便?

在 viewDidLoad: 最後面添加下面一行
復制代碼 代碼如下:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveCurrentState) name:UIApplicationDidEnterBackgroundNotification object:nil];

現在,當你的 app 進入後台運行後,ViewController 會自動調用 saveCurrentState 存儲當前的狀態。

現在,添加下面代碼:
復制代碼 代碼如下:
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

這裡是確保當 ViewController 被釋放時,移除類的 Observer。

構建和運行你的 app,點擊到一個專輯,用 Command+Shift+H(如果你使用的是模擬器的話) 將程序在後台運行,然後關掉 app。重啟 app,檢查之前選擇的專輯是不是居中顯示:

2016323170032314.png (214×320)

專輯數據看起來是對的,但是正確的專輯封面確沒有居中,哪出問題了?

這就是可選方法 initialViewIndexForHorizontalScroller 的用處!因為這個方法沒有被委托執行,ViewController 在這種情況下總是會顯示默認的第一個專輯封面。

修復這個問題,在 ViewController.m 中添加如下代碼:
復制代碼 代碼如下:
- (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller *)scroller
{
    return currentAlbumIndex;
}

現在 HorizontalScroller 的第一個視圖總是會被設置成 currentAlbumIndex 索引的圖片。這種方法能夠確保你的 app 有一個非常棒的用戶體驗,並且它是可恢復的。

重新運行你的 app,滾動專輯封面,關閉 app,然後重啟確保問題已經得到解決:

2016323170107827.png (214×320)

如果你查看 PersistencyManger 的初始化方法,你會注意到專輯的數據是一種硬編碼,PersistencyManger 每次創建,數據也會重復創建一次。有沒有一種更好的方法當專輯列表被創建的時候就存儲它們呢。那麼如何把專輯數據存儲到文件裡呢?

一種選擇就是循環訪問 Album 的屬性,然後把它存儲在一個 plist 文件裡,當需要它們的時候重新創建一個 Album 的實例。這不是最好的選擇,這需要你在每一個類裡根據不同的數據或屬性寫特定的代碼。例子,如果稍後你需要一個電影的類,裡面有一些不同的屬性,存儲和加載這些數據你就需要寫一些新的代碼。

此外,你不能在每一個類的實例裡存儲私有變量,因為他們是不可訪問的外部類。這就是為什麼蘋果要創建歸檔 (Archiving) 機制。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved