IOS設計模式第九篇之備忘錄模式 NSUserDefaults

備忘錄模式捕獲和具體化對象的內部狀態。換句話說,它可以節省你的東西后來,這種外部狀態可以恢復在不違反封裝;

也就是說,私人數據是私有的。

怎麼用備忘錄設計模式

在Viewcontroller的實現文件裏添加下面方法:

- (void)saveCurrentState

{

    // When the user leaves the app and then comes back again, he wants it to be in the exact same state

    // he left it. In order to do this we need to save the currently displayed album.

    // Since it's only one piece of information we can use NSUserDefaults.

    [[NSUserDefaults standardUserDefaults] setInteger:currentAlbumIndex forKey:@"currentAlbumIndex"];

  

}

- (void)loadPreviousState

{

    currentAlbumIndex = [[NSUserDefaults standardUserDefaults] integerForKey:@"currentAlbumIndex"];

    [self showDataForAlbumAtIndex:currentAlbumIndex];

}

saveCurrentState 保存了這個當前專輯的索引用NSUserDefaults 他是一個蘋果提供的標準的存儲應用設置和數據的。

loadPreviousState 加載之前保存的索引。這不是備忘錄設計模式的完全實現。

現在添加代碼在滑動視圖初始化前面:

[self loadPreviousState];

應用程序啓動時加載以前保存的狀態,但是你保存應用當前轉檯只是爲了加載?你將要用通知做這件事。當應用進入到後臺系統發送

UIApplicationDidEnterBackgroundNotification。你可以用這個通知調用saveCurrentState。這不是很方面嗎?

在ViewDidLoad添加下面代碼:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveCurrentState) name:UIApplicationDidEnterBackgroundNotification object:nil];

現在這個應用進入到後臺。將要自動的調用saveCurrentState方法來保存當前狀態。

現在添加下面代碼:

- (void)dealloc

{

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

這個保證你Viewcontroller銷燬的時候移除這個類註冊的觀察者。

構建和運行您的應用程序。導航到一個專輯,將應用程序發送到後臺使用命令+ Shift + H(如果你是在模擬器),然後關閉應用程序,重新啓動,並檢查之前,選擇專輯爲中心:

看起來你的專輯數據是正確的。但是你的滑動視圖沒有在中間這是怎麼了?

這就是上面可選協議方法的意義

initialViewIndexForHorizontalScroller:因爲這個方法在代理類裏面沒有實現。在這個例子代理類就是Viewcontroller,因此初始視圖一直被設置爲第一個視圖。

爲了修正他在Viewcontroller的實現文件裏面添加下面代碼:

- (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller *)scroller

{

    return currentAlbumIndex;

}

現在這個滑動視圖的第一個視圖可以設置爲任何專輯是由

currentAlbumIndex表明的。這是一個很好的方法來確保你的應用體驗來維持私有和可恢復的。

如果你看看PersistencyManager的init,你將要注意到這個專輯數據是硬件編碼並且PersistencyManager創建的時候都會重新創建。最好的解決方法是一旦創建專輯列表就把他們存儲到一個文件。那麼怎麼把專輯存儲到文件呢?

一種方法是迭代專輯的屬性,保存他們到一個plist文件並且然後創建專輯的實例一旦需要的時候。但是這不是最佳選擇,由於需要你編寫特定的代碼依靠每個類的屬性和數據。例如你接下來創建的movies類有不同的屬性,保存和加載數據需要新的代碼。

此外,你不能保存每個類的實例的私有變量,因爲他們無法訪問外部類。這就是爲什麼蘋果公司創建歸檔機制。

歸檔

蘋果的一個專門記憶模式的實現是歸檔。把一個對象轉化爲流便於保存和恢復不用向外部類暴露私有的屬性。你可以參考Apple’s Archives and Serializations Programming Guide.

那麼怎麼用歸檔呢?

首先你需要聲明專輯通過符合NSCoding協議是可以歸檔的。在專輯頭文件寫上符合NSCoding協議:

@interface Album : NSObject <NSCoding>

在實現文件裏面:

添加兩個方法:

- (void)encodeWithCoder:(NSCoder *)aCoder

{

    [aCoder encodeObject:self.year forKey:@"year"];

    [aCoder encodeObject:self.title forKey:@"album"];

    [aCoder encodeObject:self.artist forKey:@"artist"];

    [aCoder encodeObject:self.coverUrl forKey:@"cover_url"];

    [aCoder encodeObject:self.genre forKey:@"genre"];

}

- (id)initWithCoder:(NSCoder *)aDecoder

{

    self = [super init];

    if (self)

    {

        _year = [aDecoder decodeObjectForKey:@"year"];

        _title = [aDecoder decodeObjectForKey:@"album"];

        _artist = [aDecoder decodeObjectForKey:@"artist"];

        _coverUrl = [aDecoder decodeObjectForKey:@"cover_url"];

        _genre = [aDecoder decodeObjectForKey:@"genre"];

    }

    return self;

}

你調用encodeWithCoder:當你歸檔你類的一個實例時候,

相反地的當你解檔一個實例來創建一個專輯的實例。看着簡單而且強大。現在專輯類可以被歸檔了。

添加的代碼實際上保存和加載相冊的列表。

添加以下簽名(或方法原型)PersistencyManager.h:

這將是叫的方法保存相冊。

現在,添加PersistencyManager.m方法實現:

- (void)saveAlbums

{

NSString *filename = [NSHomeDirectory() stringByAppendingString:@"/Documents/albums.bin"];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:albums];

    [data writeToFile:filename atomically:YES];

}

NSKeyedArchiver檔案專輯數組名爲albums.bin的文件。

當你歸檔對象包含其他對象,

歸檔器會自動的迭代歸檔子對象並且孩子的任何子對象。

在此情況下開始對專輯類歸檔,這是專輯實例的一個數組,因此數組和專輯都支持NSCoding接口。任何在數組裏面的東西都會被歸檔。

現在在

PersistencyManager.m init方法裏添加下面代碼:

- (id)init

{

    self = [super init];

    if (self) {

NSData *data = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingString:@"/Documents/albums.bin"]];

        albums = [NSKeyedUnarchiver unarchiveObjectWithData:data];

        if (albums == nil)

        {

            albums = [NSMutableArray arrayWithArray:

                    @[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"],

                    [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"],

                    [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"],

                    [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"],

                    [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];

            [self saveAlbums];

        }

    }

    return self;

}

在新的代碼裏,

NSKeyedUnarchiver 從文件裏面加載新的專輯數據,如果他存在。如果他不存在,

立即創建相冊數據和保存它在下次加載應用程序。

你還想保存這張專輯每次應用程序進入後臺數據。

這可能不是必要的,但如果你後來添加的選項更改相冊數據

那麼你想要確保您已經保存了所有更改。

添加以下LibraryAPI.h方法簽名:

- (void)saveAlbums;

應用通過libraryAPI訪問所有的服務,這就是應用怎麼讓PersitencyManager 知道他需要保存專輯的數據。

現在添加這個方法實現到libraryAPI實現文件裏:

- (void)saveAlbums

{

    [persistencyManager saveAlbums];

}

這段代碼僅僅通過在調用LibraryAPI保存相冊到PersistencyMangaer

。和上面的代碼使用LibraryAPI觸發保存專輯的數據每當Viewcontroller保存其狀態。

編譯運行你的應用檢查是不是所有東西運行正常。

不幸的是,沒有簡單的方法來檢查數據持久性是正確的。幸運的是你可以在finder裏檢查模擬器的document文件夾看專輯的數據文件是不是被創建,但是爲了檢查是不是有改變你不得不添加改變專輯數據的功能。

但是代替改變數據,如果你添加一個選項來刪除你的專輯當你不想要的時候。此外你應該有一個撤銷的選項一旦你誤刪了專輯。

這是我們下面介紹的一個設計模式命令設計模式。

發佈了92 篇原創文章 · 獲贊 1 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章