自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

移動(dòng)開(kāi)發(fā) iOS
iPhone開(kāi)發(fā)應(yīng)用中的Archiving NSCoder是本文要介紹的內(nèi)容,舉例我們創(chuàng)建保存一個(gè)nib文件,Interface Builder把對(duì)象寫(xiě)入到nib文件就是這樣的arching過(guò)程,來(lái)看內(nèi)容。

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程是本文要介紹的內(nèi)容,一個(gè)面向?qū)ο蟪绦蛟谶\(yùn)行的時(shí)候,一般都創(chuàng)建了一個(gè)復(fù)雜的對(duì)象關(guān)系圖,經(jīng)常需要把這樣一個(gè)復(fù)雜的對(duì)象關(guān)系圖表示成字節(jié)流.這樣的過(guò)程我們叫做Archiving 如圖10.1,

這個(gè)字節(jié)流可以在網(wǎng)絡(luò)中傳送,也可以寫(xiě)入到文件中. 例如,我們創(chuàng)建保存一個(gè)nib文件,Interface Builder把對(duì)象寫(xiě)入到nib文件就是這樣的arching過(guò)程(對(duì)于Java,這個(gè)過(guò)程叫serialization)。

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

而當(dāng)從字節(jié)流中重新恢復(fù)對(duì)象關(guān)系圖的過(guò)程叫做unarchive. 例如,當(dāng)程序啟動(dòng)是,將會(huì)從nib文件中unarchive對(duì)象雖然對(duì)象包含成員變量和方法.但是只有成員變量和類(lèi)名會(huì)被archive. 換句話(huà)說(shuō),data會(huì)被archive,而code不會(huì). 所以,如果程序A archive對(duì)象,而程序B unarchive對(duì)象.那么程序A和B都要保證包含了class所連接的code. 舉個(gè)例子,在nib文件中,你使用到了Appkit framework 的NSWindow和NSButton對(duì)象.那么如果我們的程序沒(méi)有連接Appkit framework,那么我們就沒(méi)有辦法生成NSWindow和NSButton對(duì)象,因?yàn)閍rchive中只包含了data,而沒(méi)有code

有一個(gè)洗發(fā)水的廣告是這樣說(shuō)得:"我告訴了我的兩個(gè)朋友,而他們各自又告訴了自己的兩個(gè)朋友,這樣一傳十,十傳百.."寓意就是,你告訴了你的朋友,最后所有的人都開(kāi)始使用這個(gè)洗發(fā)水了. 對(duì)象archiving的工作方式和這差不多. 你archiving一個(gè)root對(duì)象. 它archiving自己相關(guān)聯(lián)的對(duì)象,那些相關(guān)聯(lián)的對(duì)象也會(huì)archiving自己相關(guān)聯(lián)的對(duì)象,依次類(lèi)推,所有相關(guān)的對(duì)象都被archiving了

archiving由2步來(lái)完成. 1,我們需要告知我們的對(duì)象要怎么樣來(lái)archive. 2. 我們需要激發(fā)archiving動(dòng)作發(fā)生

Objective-C語(yǔ)言有一個(gè)機(jī)制叫protocol, 就像java中的interface一樣. 一個(gè)protocol聲明了一系列方法.但你的類(lèi)實(shí)現(xiàn)一個(gè)protocol,那么就預(yù)定了,你的類(lèi)需要實(shí)現(xiàn)protocol中聲明的所有方法

NSCoder 和NSCoding

NSCoding是一個(gè)protocol. 如果你的類(lèi)實(shí)現(xiàn)了NSCoding.那么就要實(shí)現(xiàn)這些方法

  1. - (id)initWithCoder:(NSCoder *)coder;  
  2. - (void)encodeWithCoder:(NSCoder *)coder; 

NSCoder是archivie 字節(jié)流的抽象類(lèi).我們可以實(shí)現(xiàn)把數(shù)據(jù)寫(xiě)入一個(gè)coder,也可以從coder中讀取我們寫(xiě)入的數(shù)據(jù). 我們對(duì)象的方法initWithCoder:就是從一個(gè)coder從讀取數(shù)據(jù),然后把數(shù)據(jù)賦給成員變量. 方法encodeWithCoder: 則是把成員變量的值寫(xiě)入到coder中. 在這一章中,我們會(huì)在Person類(lèi)中實(shí)現(xiàn)這兩個(gè)方法

NSCoder是一個(gè)抽象類(lèi),我們不會(huì)直接使用它來(lái)創(chuàng)建對(duì)象. 相反,我們會(huì)使用從它繼承來(lái)的子類(lèi). 也就是我們使用 NSKeyedUnarchiver類(lèi)來(lái)從字節(jié)流中讀取數(shù)據(jù),而使用NSKeyedArchiver類(lèi)來(lái)把對(duì)象寫(xiě)入到字節(jié)流

Encoding

NSCoder包含了很多方法, 不過(guò)大部分人會(huì)發(fā)現(xiàn)只會(huì)使用到其中很少的一部分. 下面是當(dāng)要archivie數(shù)據(jù)時(shí)用到的一些常用方法

  1. - (void)encodeObject:(id)anObject forKey:(NSString *)aKey 

這個(gè)方法把a(bǔ)nObject對(duì)象寫(xiě)入到coder中,并把它和aKey關(guān)聯(lián)起來(lái)[下次使用aKey從coder中可以再把a(bǔ)nObject讀取出來(lái)] 這會(huì)是anObject的方法encodeWithCodr得到調(diào)用(還記得上面那個(gè)洗發(fā)水廣告把.就是這樣傳下去的)

對(duì)于C的基本類(lèi)型(如int float).NSCoder使用下面方法

  1. - (void)encodeBool:(BOOL)boolv forKey:(NSString *)key  
  2. - (void)encodeDouble:(double)realv forKey:(NSString *)key  
  3. - (void)encodeFloat:(float)realv forKey:(NSString *)key  
  4. - (void)encodeInt:(int)intv forKey:(NSString *)key 

添加encoing方法到Person類(lèi)中.

  1. - (void)encodeWithCoder:(NSCoder *)coder  
  2. {  
  3.     [super encodeWithCoder:coder];  
  4.     [coder encodeObject:personName forKey:@"personName"];  
  5.     [coder encodeFloat:expectedRaise forKey:@"expectedRaise"];  

這里調(diào)用了父類(lèi)的encodeWithCoder,使得父類(lèi)有機(jī)會(huì)把自己的變量寫(xiě)入到coder中. 因此,類(lèi)繼承樹(shù)中的類(lèi)只會(huì)把自己的成員變量寫(xiě)入到coder-不會(huì)包含父類(lèi)的成員變量

Decoding

從coder中decoding數(shù)據(jù),我們使用這些方法

  1. - (id)decodeObjectForKey:(NSString *)aKey  
  2. - (BOOL)decodeBoolForKey:(NSString *)key  
  3. - (double)decodeDoubleForKey:(NSString *)key  
  4. - (float)decodeFloatForKey:(NSString *)key  
  5. - (int)decodeIntForKey:(NSString *)key 

如果因?yàn)槟承┰? 字節(jié)流中沒(méi)有和aKey關(guān)聯(lián)的數(shù)據(jù),那么我們會(huì)得到0值. 例如,對(duì)象沒(méi)有把key foo 關(guān)聯(lián)一個(gè)float數(shù)據(jù)寫(xiě)入coder,那么在使用foo key來(lái)讀取這個(gè)float數(shù)據(jù),coder會(huì)返回0.0 . 如果key foo關(guān)聯(lián)的是一個(gè)對(duì)象數(shù)據(jù)[使用方法encodeWithCoder 寫(xiě)入],那么讀取時(shí)coder返回nil

添加decoding到Person類(lèi)中

  1. - (id)initWithCoder:(NSCoder *)coder  
  2. {  
  3.    [super init];  
  4.    personName = [[coder decodeObjectForKey:@"personName"] retain];  
  5.    expectedRaise = [coder decodeFloatForKey:@"expectedRaise"];  
  6.    return self;  

我們沒(méi)有調(diào)用父類(lèi)的initWithCoder, 那是因?yàn)镹SObject沒(méi)有實(shí)現(xiàn)它. 如過(guò)Person類(lèi)的父類(lèi)實(shí)現(xiàn)了NSCoding協(xié)議,那么這個(gè)方法應(yīng)該這樣寫(xiě)

  1. - (id)initWithCoder:(NSCoder *)coder  
  2. {  
  3.   [super initWithCoder:coder];  
  4.   personName = [[coder decodeObjectForKey:@"personName"] retain];  
  5.   expectedRaise = [coder decodeFloatForKey:@"expectedRaise"];  
  6.   return self;  

你可以會(huì)說(shuō)"在第3章中, designated initializer會(huì)完成所有的init工作然后在調(diào)用父類(lèi)的 designated initializer, 也就是說(shuō)類(lèi)的其他initializer 方法都會(huì)調(diào)用designated initializer,Person類(lèi)有designated initializer- init. 可以這個(gè)新加入的initializer方法并沒(méi)有調(diào)用init方法阿?" 不錯(cuò), 你是對(duì)的, initWithCoer: 是這個(gè)規(guī)則的一個(gè)特例.

好了.我們實(shí)現(xiàn)了NSCoding協(xié)議的方法.現(xiàn)在讓Person類(lèi)實(shí)現(xiàn)NSCoding protocol. 我們來(lái)編輯Person.h文件.

  1. @interface Person : NSObject <NSCoding> { 

現(xiàn)在編譯我們的工程. 你也可以運(yùn)行程序看看.雖然Person類(lèi)可以encode自己了.不過(guò)我們沒(méi)有地方讓它這么做.所以程序看上去沒(méi)什么變化.

#p#

Document Architecture

多文檔程序有很多的共同性. 比如都可以創(chuàng)建新的document, 打開(kāi)document,保存或打印打開(kāi)的document, 當(dāng)關(guān)閉document窗口或退出程序時(shí)提醒用戶(hù)保存編輯好得document. Apple提供3個(gè)類(lèi)- NSDocumentController,NSDocument,NSWindowController-來(lái)完成這些工作. 它們一起組成了document architecture

創(chuàng)建document architecture的意圖是和我們第8章討論的Model-View-Controller設(shè)計(jì)模式相關(guān)的. 在RaiseMan工程中. 我們的NSDocument子類(lèi)-使用了NSArrayController類(lèi)-就是其中的Controller. 它包含了指向model對(duì)象的指針. 負(fù)責(zé)下面所列的職責(zé) [這里的model 數(shù)據(jù)就是值employyess-person 對(duì)象]

將model 數(shù)據(jù)保存為一個(gè)文件

從一個(gè)文件中加載model數(shù)據(jù)

在view中顯示model數(shù)據(jù)

響應(yīng)用戶(hù)通過(guò)view的輸入,并更新model

Info.plist 和 NSDocumentController

XCode在編譯創(chuàng)建一個(gè)程序時(shí)會(huì)使用到一個(gè)文件 Info.plist(本章后面,我們會(huì)修改這個(gè)文件). 當(dāng)程序啟動(dòng)時(shí),它會(huì)讀取Info.plisst的信息. 告知工作的文件類(lèi)型是什么. 如果它發(fā)現(xiàn)是一個(gè)document-base 程序. 那么會(huì)創(chuàng)建一個(gè)NSDocumentController對(duì)象(圖10.2). 我們很少去直接使用這個(gè)document controller. NSDocumentController對(duì)象在后面會(huì)為我們做一些工作.例如,當(dāng)選擇New 或是 Save All菜單時(shí), document controller會(huì)處理這些請(qǐng)求. 如果你有給document controller發(fā)送消息,你可以這樣做

  1. NSDocumentController *dc;  
  2. dc = [NSDocumentController sharedDocumentController]; 

 

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

document controller保存了一個(gè)document 對(duì)象的array - 每一個(gè)document對(duì)象就是一個(gè)打開(kāi)的document.

NSDocument

document對(duì)象是NSDocument子類(lèi)的一個(gè)實(shí)例. 在我們的RaiseMan程序中,它就是MyDocument的實(shí)例. 對(duì)于大部分程序,一般我們只有簡(jiǎn)單的擴(kuò)展NSDocument來(lái)完成想要的功能而不需要過(guò)多關(guān)系NSDocumentcontroller或是NSWindowController

saving

菜單項(xiàng)Save,Save As...,Save All,和Close雖然不相同.但是它們都面向同一個(gè)問(wèn)題:把mdoel保存為一個(gè)文件或是文件包(文件包是一個(gè)文件目錄,不過(guò)對(duì)于用戶(hù)就象是一個(gè)文件一樣). 對(duì)于這些菜單項(xiàng). 我們的NSDocument子類(lèi)需要實(shí)現(xiàn)下面3個(gè)方法中的一個(gè)

  1. - (NSData *)dataOfType:(NSString *)aType  
  2.                  error:(NSError *)e 

你的document對(duì)象將model生成一個(gè)NSData寫(xiě)入文件.[這個(gè)方法中,我們只有把model壓成一個(gè)NSData返回,然后Cocoa會(huì)把NSData在寫(xiě)入文件了] NSData就是字節(jié)buffer. 是簡(jiǎn)單也是通用的實(shí)現(xiàn)saving的方法.如果不能生成一個(gè)NSData 對(duì)象,那么就返回nil,而用戶(hù)會(huì)得到一個(gè)alert提示save失敗. 注意到參數(shù)aType, 它可以容許你將document保存為一個(gè)或多個(gè)類(lèi)型格式. 例如,你編寫(xiě)了一個(gè)圖像程序,你可能容許用戶(hù)將圖像保存為gif或是jpg格式.所以當(dāng)你生成data對(duì)象時(shí), aType就指定了用戶(hù)請(qǐng)求保存的格式.如果你的程序只處理單一類(lèi)型,那么可以忽略aType. 為了說(shuō)明你不能保存,可以返回nil并創(chuàng)建一個(gè)NSError對(duì)象來(lái)說(shuō)明出來(lái)什么樣得錯(cuò)誤

  1. - (NSFileWrapper *)fileWrapperOfType:(NSString *)aType  
  2.                                error:(NSError *)e 

你的document對(duì)象生成一個(gè)文件包返回. 文件包將被創(chuàng)建在用戶(hù)指定的位置

  1. - (BOOL)writeToURL:(NSURL *)absoluteURL  
  2.             ofType:(NSString *)typeName  
  3.              error:(NSError **)outError; 

你的docuemnt對(duì)象以指定的type把model數(shù)據(jù)保存在指定的URL(URL就是文件系統(tǒng)上的文件路徑)[這個(gè)方法應(yīng)該在NSDocument類(lèi)中實(shí)現(xiàn)了,里面估計(jì)就是調(diào)用了dataOfType:error: . 得到NSData后將其寫(xiě)入指定URL. 當(dāng)然你也可以從中這個(gè)方法] 如果能夠保存成功返回YES,否則返回NO. 如果返回NO,那么你你應(yīng)該生成一個(gè)NSError對(duì)象來(lái)描述錯(cuò)誤是什么

來(lái)解釋下NSError.它的觀念是,因?yàn)槟承┰?某個(gè)方法沒(méi)有辦法完成這個(gè)功能.那么它就會(huì)生成一個(gè)NSError對(duì)象,并把NSError對(duì)象的指針?lè)诺街付ǖ奈恢? 例如,如果我希望從一個(gè)文件中讀取到一個(gè)NSData,那么我會(huì)提供一個(gè)地址,當(dāng)出錯(cuò)時(shí),我可以從這個(gè)地址中得到錯(cuò)誤信息
NSError *e;

  1. NSData *d = [NSData dataWithContentsOfFile:@"/tmp/x.txt"  
  2.                                    options:0  
  3.                                      error:&error];  
  4. // Did the read fail?  
  5. if (d == nil) {  
  6.       NSLog(@"Read failed: %@", [error localizedDescription];  

所以NSData類(lèi)即會(huì)返回一個(gè)data對(duì)象,同時(shí)可能會(huì)創(chuàng)建一個(gè)error對(duì)象

在save和load方法中,我們將有負(fù)責(zé)在失敗的時(shí)候創(chuàng)建NSError對(duì)象

Loading

Open...,Open Recent,和Revert To Saved 菜單項(xiàng)也是一樣,它們都面向同一個(gè)問(wèn)題:從一個(gè)文件或是文件包中得到model. 為了響應(yīng)它們,NSDocuement子類(lèi)需要實(shí)現(xiàn)下面3個(gè)方法中的一個(gè)

  1. - (BOOL)readFromData:(NSData *)data  
  2.               ofType:(NSString *)typeName  
  3.                error:(NSError **)outError 

包含了用戶(hù)要打開(kāi)的文件內(nèi)容的NSData對(duì)象被傳進(jìn)來(lái). 如果能夠從這個(gè)NSData對(duì)象中生成model那么就返回YES. 如果返回NO,那么用戶(hù)會(huì)得到一個(gè)Alert提示為什么個(gè)不能成功打開(kāi)文件. Alert的內(nèi)容由這個(gè)方法生成的NSError對(duì)象來(lái)指定

  1. - (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper  
  2.                      ofType:(NSString *)typeName  
  3.                       error:(NSError **)outError; 

從一個(gè)NSFileWrapper對(duì)象讀取model數(shù)據(jù)

  1. - (BOOL)readFromURL:(NSURL *)absoluteURL  
  2.              ofType:(NSString *)typeName  
  3.               error:(NSError **)outError; 

#p#

從指定文件中讀取model數(shù)據(jù)

在實(shí)現(xiàn)了一個(gè)save和一個(gè)load方法后,我們的程序就知道怎么樣讀寫(xiě)文件了.在打開(kāi)一個(gè)文件時(shí), document對(duì)象會(huì)在讀取nib文件前讀取document文件[你需要讀取nib文件來(lái)顯示一個(gè)document阿] . 這樣的結(jié)果是,我們不能在loading一個(gè)document文件后馬上去給用戶(hù)界面發(fā)送消息(它們還不存在)[注意load nib文件是document 架構(gòu)為我們做的,這里說(shuō)的立馬調(diào)用是指在 load方法中-這個(gè)是我們?cè)贜SDocument子類(lèi)中實(shí)現(xiàn)的調(diào)用-給UI發(fā)送消息]. [那如果我們想要馬上給UI發(fā)送消息怎么辦?]-為了解決這個(gè)問(wèn)題,我們可以實(shí)現(xiàn)一個(gè)方法-它會(huì)在nib文件被調(diào)用UI創(chuàng)建好了后發(fā)送

  1. - (void)windowControllerDidLoadNib:(NSWindowController *)x; 

[想想 當(dāng)點(diǎn)擊Open菜單,代碼執(zhí)行的過(guò)程是怎么樣 - 有些代碼是cocoa里面實(shí)現(xiàn)的,有些是我們自己實(shí)現(xiàn)的]

在我們的NSDocuemnt 子類(lèi)中,實(shí)現(xiàn)這個(gè)方法刷新UI

NSWindowController

在document architecture中最后要介紹的一個(gè)類(lèi)是NSWindowcontroller .每打開(kāi)一個(gè)Document都會(huì)產(chǎn)生一個(gè)窗口-生成一個(gè)NSWindowController實(shí)例. 對(duì)于大部分程序,每一個(gè)document對(duì)于一個(gè)window, window controller的默認(rèn)實(shí)現(xiàn)已經(jīng)夠用了.所以一般我們只有在下面幾種情況下才會(huì)生成一個(gè)NSWindowController的子類(lèi)

對(duì)于同一個(gè)document,需要使用多個(gè)window. 例如,CAD程序, 你可能需要一個(gè)text窗口來(lái)描述一個(gè)立體,而另外一個(gè)窗口來(lái)顯示這個(gè)立體

你需要把UI controller 和 model controller 放到不同的類(lèi)中

你需要?jiǎng)?chuàng)建不和NSDocument 對(duì)象對(duì)應(yīng)的窗口.我們會(huì)在12章來(lái)做這樣的事

Saving 和 NSKeyedArchiver

現(xiàn)在我們知道了怎樣encode和decode我們自己的類(lèi),現(xiàn)在開(kāi)始給我們的程序添加saving和loading功能了. 當(dāng)我們要保存person到一個(gè)文件,MyDocument類(lèi)會(huì)被請(qǐng)求生成一個(gè)NSData實(shí)例. 一旦創(chuàng)建了NSData實(shí)例并返回,它會(huì)自動(dòng)保存到文件中

為了生成一個(gè)NSData實(shí)例[encode了model數(shù)據(jù)] , 我們使用NSKeyedArchiver類(lèi). 它有這樣一個(gè)方法

  1. + (NSData *)archivedDataWithRootObject:(id)rootObject 

這個(gè)方法將對(duì)象archive成NSData對(duì)象的字節(jié)buffer [字節(jié)buffe-看看NSData的說(shuō)明吧]

再一次回到那個(gè)廣告"我告訴了兩朋友,他們也告訴了自己的朋友...."當(dāng)你encode一個(gè)對(duì)象是, 這個(gè)對(duì)象會(huì)encode它自己連接的對(duì)象,那些對(duì)象也會(huì)encode它們連接的對(duì)象..等等. 這里我們要encode那個(gè)對(duì)象呢?就是array employees了. 它又會(huì)encode所有包含的Person對(duì)象. 而我們?cè)赑eron類(lèi)中實(shí)現(xiàn)了encodeWithCoder:,所以每個(gè)Perosn對(duì)象開(kāi)始encode自己了-encode personName字串和expectedRaise float

編輯方法dataOfType:error:. 添加saving功能

  1. - (NSData *)dataOfType:(NSString *)aType  
  2.                  error:(NSError **)outError  
  3. {  
  4.     // End editing  
  5.     [[tableView window] endEditingFor:nil];  
  6.  
  7.     // Create an NSData object from the employees array  
  8.     return [NSKeyedArchiver archivedDataWithRootObject:employees];  

這里我們忽略了error參數(shù).將沒(méi)有error產(chǎn)生

  1. Loading和NSKeyedUnarchiver 

現(xiàn)在開(kāi)始添加load文件功能, 再一次說(shuō)明,NSDocument已經(jīng)大部分細(xì)節(jié)

我們會(huì)使用到NSKeyedUnarchiver類(lèi)方法

  1. + (id)unarchiveObjectWithData:(NSData *)data 

編輯MyDocument類(lèi)的readFromData:ofType:error:方法

  1.               ofType:(NSString *)typeName  
  2.                error:(NSError **)outError  
  3. {  
  4.    NSLog(@"About to read data of type %@", typeName);  
  5.    NSMutableArray *newArray = nil;  
  6.    @try {  
  7.       newArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];  
  8.    }  
  9.    @catch (NSException *e) {  
  10.       if (outError) {  
  11.          NSDictionary *d = [NSDictionary  
  12.               dictionaryWithObject:@"The data is corrupted."  
  13.                             forKey:NSLocalizedFailureReasonErrorKey];  
  14.          *outError = [NSError errorWithDomain:NSOSStatusErrorDomain  
  15.                                          code:unimpErr  
  16.                                      userInfo:d];  
  17.       }  
  18.       return NO;  
  19. }  
  20.    [self setEmployees:newArray];  
  21.    return YES;  

在nib文件加載后,你需要刷新UI.不過(guò)NSArrayController為你完成了這個(gè)功能.我們不需要在windowControllerDidLoadNib:方法中多做什么. 我們?cè)?3章將會(huì)修改這個(gè)方法

  1. - (void)windowControllerDidLoadNib:(NSWindowController *)aController  
  2. {  
  3.     [super windowControllerDidLoadNib:aController];  

注意,在打開(kāi)或創(chuàng)建一個(gè)document時(shí),會(huì)詢(xún)問(wèn)我們的document類(lèi):需要load那個(gè)nib文件.現(xiàn)在我們也不需要修改這個(gè)方法

  1. - (NSString *)windowNibName  
  2. {  
  3.     return @"MyDocument";  

因?yàn)槲覀兗せ盍藆ndo 機(jī)制,所以在編輯了document后, window會(huì)自動(dòng)標(biāo)注為編輯過(guò).

現(xiàn)在,我們的程序能夠讀寫(xiě)文件了.編譯運(yùn)行程序,試試看吧,看上去都能工作正常. 不過(guò)我們保存的文件的后綴名為.???? ,我們需要在Info.plist中給它定義一個(gè)后綴名

#p#

設(shè)置后綴名和圖標(biāo)

我們將為RaiseMan 文件添加后綴.rsmn 和一個(gè)圖標(biāo). 首先找到一個(gè).icns文件并拷貝到我們的工程中. 就使用

  1. /Developer/Examples/Appkit/CompositeLab/BBall.icns 

吧.把他從Finder中拖到XCode的Resources組中.如圖10.3

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

XCode會(huì)彈出一個(gè)頁(yè)面,確保勾選Copy items into destination group's folder 如圖10.4.這樣將會(huì)包icon文件拷貝到我們的工程目錄中

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

在XCode中選定RaiseMan Target, 從File菜單中選擇Get Info, 來(lái)設(shè)置document-type屬性. 在Properties頁(yè)中,設(shè)置identifier為com.bignerdranch.RaiseMan. 設(shè)置Icon file 為BBall. 在document-types中,設(shè)置name為RaiseMan Doc. Extensions為rsmn. icon file為BBall.參考圖10.5

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

編譯運(yùn)行程序.我們?cè)俅卧囋嚤4婧痛蜷_(kāi)功能. 在Finder中, 我們的.rsmn文件的圖標(biāo)變成了BBall.icns

一個(gè)程序其實(shí)是一個(gè)目錄. 包含了程序用到的nib 文件, 圖像,聲音和可執(zhí)行代碼. 在Terminal,試試輸入

  1. cd /Applications/TextEdit.app/Contents  
  2. ls 

可以看到3個(gè)有趣的東西

Info.plist文件. 包含了該程序的信息, 文件類(lèi)型和相關(guān)的圖標(biāo). Finder會(huì)使用這些信息

MacOS/目錄. 這里包含了可執(zhí)行代碼

Resources/目錄. 這里包含了程序用到的圖像,聲音和nib文件,你還可以看到不同語(yǔ)言的本地化資源

#p#

思考:避免死循環(huán)

聰明的讀者可能會(huì)懷疑:""如果對(duì)象A使對(duì)象B進(jìn)行encode,對(duì)象B使對(duì)象C進(jìn)行encode,而對(duì)象C又使得對(duì)象A進(jìn)行encode. 這樣不是會(huì)產(chǎn)生無(wú)窮循環(huán)嗎?"" 沒(méi)錯(cuò),確實(shí)會(huì)發(fā)生這種情況,好在NSKeyedArchiver類(lèi)設(shè)計(jì)好了避免這種情況發(fā)送.

當(dāng)encode一個(gè)對(duì)象的時(shí)候,會(huì)將一個(gè)唯一標(biāo)識(shí)同時(shí)放到流中.并建立一個(gè)表,一旦archive對(duì)象,就會(huì)把該對(duì)象和它的唯一標(biāo)識(shí)聯(lián)系起來(lái). 如果下次又要encode同一個(gè)對(duì)象,NSKeyedArchiver會(huì)先瀏覽這個(gè)表,看是否已經(jīng)encode過(guò),并只會(huì)把唯一標(biāo)識(shí)放置到流中.

當(dāng)從流中decode出對(duì)象時(shí), NSKeyedUnarchiver同樣會(huì)生成一個(gè)表,把encode對(duì)象和唯一標(biāo)識(shí)關(guān)聯(lián)起來(lái).如果發(fā)現(xiàn)流中只有唯一標(biāo)識(shí)[說(shuō)明之前有encode這個(gè)對(duì)象],unarchiver就會(huì)在表中來(lái)查找這個(gè)對(duì)象,而不是再生成一個(gè)新的對(duì)象.

NSCoder有一個(gè)方法容易使讀者和上面的思想產(chǎn)生混淆

  1. - (void)encodeConditionalObject:(id)anObject forKey:(NSString *)aKey 

當(dāng)對(duì)象A有一個(gè)指針指向?qū)ο驜, 但是對(duì)象A不需要知道對(duì)象B是否被archive[是否存在]. 不過(guò)如果另外一個(gè)對(duì)象已經(jīng)archive了B,對(duì)象A又希望將對(duì)象B的唯一標(biāo)識(shí)在encode的時(shí)候能夠放置到流中.  [也就是說(shuō)對(duì)象A不會(huì)主動(dòng)encode B, 如果存在對(duì)象B ,那么就指向它,否則就指向空]

舉個(gè)例子,我們需要給Engine對(duì)象編寫(xiě)它的encodeWithCoder:方法. 它有一個(gè)成員變量為car,是一個(gè)指向Car對(duì)象的指針(發(fā)動(dòng)機(jī)是汽車(chē)的一部分). 我們?cè)?strong>archiving Engine對(duì)象時(shí),不希望整個(gè)Car對(duì)象被archived. 不過(guò)如果該Car對(duì)象之前在其他地方archived過(guò), 我們又希望 Engine對(duì)象的car指針指向它. 在這種情況下,我們就要要求Engine對(duì)象有條件的來(lái)encode car指針指向的對(duì)象了. 如圖10.6

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

思考: 創(chuàng)建Protocol

創(chuàng)建自己的Protocol非常簡(jiǎn)單.下面的Protocol有兩個(gè)方法,它可能在Foo.h文件中

  1. @protocol Foo  
  2. - (void)fido:(int)x;  
  3. - (float)rex;  
  4. @end 

Objective-C 2.0中,新增了語(yǔ)法@optional. 可以用來(lái)指定那些方法是必須那些方法是可選的

  1. @protocol Foo  
  2. - (void)fido:(int)x;  
  3. - (float)rex;  
  4. @optional  
  5. - (int)rover;  
  6. - (void)spot:(int)x;  
  7. @end 

在這個(gè)例子中fido: 和rex方法是必須的,而rover和spot:方法是可選的

如果你有一個(gè)類(lèi)要實(shí)現(xiàn)Foo protocol和NSCoding protocol. 應(yīng)該這樣做

  1. #import "Spunky.h"  
  2. #import "Foo.h"  
  3.  
  4. @interface ZsaZsa:Spunky <Foo, NSCoding> 
  5. ...etc...  
  6. @end 

我們不需要重新聲明父類(lèi)和protocol中聲明過(guò)的方法.所以,在本例中, ZsaZsa類(lèi)接口文件中不需要再次聲明Spunky和Foo,NSCoding中聲明過(guò)的方法

通用類(lèi)型描述[UTI]

在使用計(jì)算機(jī)時(shí),一直有這樣一個(gè)問(wèn)題:"數(shù)據(jù)是怎么樣展現(xiàn)出來(lái)的". 對(duì)于Mac, 這個(gè)問(wèn)題在不同的幾個(gè)地方都會(huì)遇到:當(dāng)從Finder打開(kāi)一個(gè)文件時(shí).當(dāng)通過(guò)剪貼板拷貝數(shù)據(jù)時(shí),當(dāng)通過(guò)Spotlight索引文件時(shí),當(dāng)使用Quicklook預(yù)覽文件時(shí).這個(gè)問(wèn)題有一些答案: 文件擴(kuò)展名, creator codes,和MIME類(lèi)型

Apple選擇的長(zhǎng)期解決途徑是通用類(lèi)型描述(UTIs). 一個(gè)UTI是一個(gè)描述了文件類(lèi)型的字符串. UTIs按一定層次關(guān)系組織.

我們?cè)贗nfo.plist文件中定義程序可以讀寫(xiě)的UTIs-包括新建的和自定義的UTIs. Info.plist文件是XML格式,包含了目錄以及key-value.  可以使用一個(gè)新key UTExporterTypeDeclarations來(lái)export新的UTIs. 例如,如果你想給RaiseMain Document添加一個(gè)UTI. 可以在Info.plist文件中添加如下描述:

  1. <array> 
  2.     <dict> 
  3.         <key>UTTypeIdentifier</key> 
  4.         <string>com.bignerdranch.raiseman-doc</string> 
  5.         <key>UTTypeDescription</key> 
  6.         <string>RaiseMan Document</string> 
  7.         <key>UTTypeConformsTo</key> 
  8.         <array> 
  9.               <string>public.data</string> 
  10.         </array> 
  11.         <key>UTTypeTagSpecification</key> 
  12.  
  13.         <dict> 
  14.               <key>com.apple.ostype</key> 
  15.               <string>rsmn</string> 
  16.               <key>public.filename-extension</key> 
  17.               <array> 
  18.                    <string>rsmn</string> 
  19.               </array> 
  20.         </dict> 
  21.      </dict> 
  22. </array> 

當(dāng)然,我們也通過(guò)properties inspector來(lái)使用UTI.如圖10.7

iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程

你可以在Apple的文檔中找到所有的系統(tǒng)定義的UTIs

小結(jié):iPhone開(kāi)發(fā)應(yīng)用之Archiving NSCoder教程的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!

責(zé)任編輯:zhaolei 來(lái)源: 新浪博客
相關(guān)推薦

2011-08-11 10:16:23

iPhoneUIView視圖

2011-08-11 10:27:37

iPhoneUIView視圖

2011-08-16 19:02:23

iPhone開(kāi)發(fā)繪圖

2011-08-10 15:36:26

iPhone靜態(tài)庫(kù)控件

2011-08-15 18:02:32

iPhone開(kāi)發(fā)表視圖

2011-07-08 14:58:16

iPhone Xcode iOS

2011-08-11 11:51:07

iPhone鍵盤(pán)

2011-08-12 11:31:46

iPhoneUIView動(dòng)畫(huà)

2011-08-15 10:15:00

iPhone開(kāi)發(fā)警告框

2011-08-09 13:10:32

iPhone地圖開(kāi)發(fā)

2011-08-19 14:27:29

iPhone開(kāi)發(fā)

2011-08-08 18:19:09

iPhone音頻播放

2011-08-11 17:32:51

iPhone視圖

2011-08-12 10:16:10

iPhone通訊錄聯(lián)系人

2011-08-15 13:44:07

iPhone開(kāi)發(fā)UITableView

2011-08-10 15:48:10

iPhone網(wǎng)絡(luò)

2011-07-08 16:02:24

iphone

2011-08-10 18:24:22

iPhone 圖形 繪圖

2011-08-02 17:37:01

IPhone開(kāi)發(fā) 環(huán)境搭建

2011-07-18 09:35:29

iPhone 框架
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)