簡介
在Foundation框架和Core Foundation框架可以將二進(jìn)制封裝為對(duì)象并對(duì)其進(jìn)行操作。因?yàn)閿?shù)據(jù)對(duì)象是橋接對(duì)象樊展,所以開發(fā)者可以交替使用Core Foundation數(shù)據(jù)對(duì)象和Foundation對(duì)象腾窝。數(shù)據(jù)對(duì)象可以自動(dòng)管理字節(jié)緩沖區(qū)的內(nèi)存開辟和內(nèi)存釋放。數(shù)據(jù)對(duì)象可以被存儲(chǔ)在集合中井氢,吸入屬性列表,存儲(chǔ)在文件中岳链,以及在通訊端口之間進(jìn)行傳輸花竞。
本文檔的結(jié)構(gòu)
下面的文章介紹了數(shù)據(jù)對(duì)象是如何運(yùn)作的
《數(shù)據(jù)對(duì)象》描述了數(shù)據(jù)對(duì)象是如何對(duì)緩沖字節(jié)進(jìn)行封裝的
下面的文章介紹了一般的任務(wù)
《二進(jìn)制數(shù)據(jù)的使用》解釋了如何創(chuàng)建和使用二進(jìn)制數(shù)據(jù)對(duì)象
《可變二進(jìn)制數(shù)據(jù)的使用》解釋了如何修改二進(jìn)制數(shù)據(jù)對(duì)象中的字節(jié)緩沖
數(shù)據(jù)對(duì)象
數(shù)據(jù)對(duì)象就是對(duì)緩沖字節(jié)進(jìn)行面向?qū)ο蠡姆庋b宅静。在這些數(shù)據(jù)對(duì)象中糟描,簡單開辟的緩存區(qū)(也就是不包含嵌套指針)具有其他對(duì)象的一些行為—也就是說碑定,它們既能夠包含數(shù)據(jù)叁扫,又能提供對(duì)這些數(shù)據(jù)的操作方法吼鱼。數(shù)據(jù)對(duì)象通常被用來存儲(chǔ)數(shù)據(jù)供鸠。數(shù)據(jù)對(duì)象在互聯(lián)網(wǎng)以及內(nèi)部網(wǎng)絡(luò)的應(yīng)用中非常有用密末,因?yàn)閿?shù)據(jù)對(duì)象中被包含的數(shù)據(jù)可以在應(yīng)用之間進(jìn)行傳輸抢腐。
一個(gè)NSData或者NSMutableData對(duì)象所能夠封裝的數(shù)據(jù)大小取決于對(duì)應(yīng)的平臺(tái)限制摔癣,相關(guān)細(xì)節(jié)請(qǐng)參照NSData文檔奴饮。當(dāng)數(shù)據(jù)大小略大于幾個(gè)內(nèi)存頁的時(shí)候,目標(biāo)對(duì)象就會(huì)使用虛擬內(nèi)存管理機(jī)制择浊。數(shù)據(jù)對(duì)象還可以對(duì)已有數(shù)據(jù)進(jìn)行封裝拐云,而不用考慮這些數(shù)據(jù)是如何被創(chuàng)建的。數(shù)據(jù)對(duì)象不會(huì)保存和緩沖數(shù)據(jù)有關(guān)的其他信息(比如數(shù)據(jù)的類型)近她;如何使用數(shù)據(jù)取決于客戶端叉瘩。尤其要注意的是,數(shù)據(jù)對(duì)象并不負(fù)責(zé)在大小端設(shè)備之間的相關(guān)轉(zhuǎn)換粘捎。取而代之的方案是薇缅,針對(duì)相關(guān)類型對(duì)象使用NSValue進(jìn)行管理危彩。
數(shù)據(jù)對(duì)象提供了一種與操作系統(tǒng)無關(guān)的方式來實(shí)現(xiàn)寫時(shí)拷貝。所謂的寫時(shí)拷貝技術(shù)就是說泳桦,當(dāng)數(shù)據(jù)從虛擬內(nèi)存進(jìn)行拷貝的時(shí)候汤徽,只有操作方試圖對(duì)目標(biāo)數(shù)據(jù)進(jìn)行修改的時(shí)候,才會(huì)真正地執(zhí)行拷貝操作灸撰。
一種典型操作就是當(dāng)創(chuàng)建一個(gè)數(shù)據(jù)對(duì)象的時(shí)候谒府,可以指定緩存區(qū)的大小。開發(fā)者還可以提取指定范圍的緩存數(shù)據(jù)浮毯,對(duì)兩個(gè)數(shù)據(jù)對(duì)象的數(shù)據(jù)進(jìn)行比較完疫,以及將數(shù)據(jù)寫入到對(duì)應(yīng)的URL中。當(dāng)創(chuàng)建了對(duì)應(yīng)的對(duì)象之后债蓝,如果還有修改對(duì)象的需求壳鹤,那么就應(yīng)該使用可修改對(duì)象。在可修改對(duì)象中饰迹,開發(fā)者可以對(duì)數(shù)據(jù)進(jìn)行截?cái)喾际摹U(kuò)展、添加啊鸭,以及替換锹淌。
使用二進(jìn)制數(shù)據(jù)
本節(jié)包含NSData以及NSMutableData的相關(guān)代碼示例。因?yàn)镕oundation中的類簇機(jī)制赠制,數(shù)據(jù)對(duì)象并不是NSData或者NSMutableData的實(shí)例葛圃,而是某個(gè)對(duì)應(yīng)的私有子類的實(shí)例。盡管一個(gè)數(shù)據(jù)對(duì)象的類是私有的憎妙,但是接口是公開的,這些接口在父類NSData和NSMutableData中進(jìn)行了聲明曲楚。
基于原始字節(jié)創(chuàng)建數(shù)據(jù)對(duì)象
通常厘唾,開發(fā)者可以在NSData或者NSMutableData中通過那些以data...開頭的方法來基于原始字節(jié)創(chuàng)建數(shù)據(jù)對(duì)象。這些方法可以返回包含開發(fā)者指定原始字節(jié)的數(shù)據(jù)對(duì)象龙誊。
通常初始化方法(諸如dataWithBytes:length:)會(huì)對(duì)傳入的緩沖區(qū)字節(jié)進(jìn)行拷貝抚垃。在這種情況下,被拷貝的
字節(jié)擁有者就是數(shù)據(jù)對(duì)象趟大,由數(shù)據(jù)對(duì)象來負(fù)責(zé)對(duì)相關(guān)內(nèi)存的釋放鹤树。而原有緩沖字節(jié)的內(nèi)存釋放則由原有對(duì)象負(fù)責(zé)。
但是逊朽,如果開發(fā)者使用了帶有NoCopy相關(guān)字樣的初始化函數(shù)罕伯,那么對(duì)應(yīng)的緩沖字節(jié)就不會(huì)被拷貝。這種情況下的數(shù)據(jù)對(duì)象會(huì)持有通過參數(shù)傳入的緩沖字節(jié)叽讳,然后在對(duì)象釋放的時(shí)候追他, 緩沖字節(jié)對(duì)應(yīng)的內(nèi)存可會(huì)被釋放掉坟募。(NSMutableData同樣也有這些方法,但是緩沖字節(jié)會(huì)被拷貝邑狸,對(duì)應(yīng)的緩沖區(qū)可會(huì)被立刻釋放掉)懈糯。基于上述原因单雾,通過NoCopy方法傳入的數(shù)據(jù)必須是通過malloc創(chuàng)建的赚哗。
如果開發(fā)者傾向于不拷貝數(shù)據(jù)或者當(dāng)對(duì)象釋放的時(shí)候,緩存字節(jié)不被釋放硅堆,那么就可以使用dataWithBytesNoCopy:length:freeWhenDone:以及initWithBytsNoCopy:length:freeWhenDone屿储,然后通過對(duì)freeWhenDone:參數(shù)傳入NO來達(dá)到目的。
基于文件或者URL創(chuàng)建數(shù)據(jù)對(duì)象
開發(fā)者可以使用dataWithContentsOfFile:以及dataWithContentsOfURL:這兩個(gè)方法來創(chuàng)建數(shù)據(jù)對(duì)象硬萍。下面是實(shí)例代碼扩所,注意,路徑必須是絕對(duì)路徑朴乖。
NSString *thePath = @"/u/smith/myFile.txt";
NSData *myData = [NSData dataWithContentsOfFile:thePath];
訪問和比較緩沖字節(jié)
NSData中的兩個(gè)基礎(chǔ)方法bytes和length為這個(gè)類的其他方法提供了基礎(chǔ)操作祖屏。bytes方法返回一個(gè)指向緩沖字節(jié)數(shù)據(jù)的指針。length方法則返回了緩沖字節(jié)的長度买羞。
NSData提供了從數(shù)據(jù)對(duì)象中拷貝到指定緩沖區(qū)的數(shù)據(jù)訪問方法袁勺。getBytes:length:方法將字節(jié)拷貝到指定緩沖區(qū)去。比如說畜普,下面的代碼段就是初始化一個(gè)數(shù)據(jù)對(duì)象myData期丰,參數(shù)是myString,然后使用了getByts:length:方法來將myData的數(shù)據(jù)拷貝到aBuffer中吃挑。
unsigned char aBuffer[20];
NSString *myString = @"Test string.";
const char *utfString = [myString UTF8String];
NSData *myData = [NSData dataWithBytes: utfString length: strlen(utfString)];
[myData getBytes:aBuffer length:20];
getBytes:range:方法將指定范圍內(nèi)的字節(jié)進(jìn)行拷貝钝荡。
為了提取某個(gè)數(shù)據(jù)對(duì)象的字節(jié)數(shù)據(jù)子集,開發(fā)者可以使用subDataWithRange:方法舶衬。舉例來說埠通,下面的代碼段會(huì)初始化一個(gè)數(shù)據(jù)對(duì)象data2來包含data1的數(shù)據(jù)子集。
NSString *myString = @"ABCDEFG";
const char *utfString = [myString UTF8String];
NSRange range = {2, 4};
NSData *data1, *data2;
data1 = [NSData dataWithBytes:utfString length:strlen(utfString)];
data2 = [data1 subdataWithRange:range];
如果想要比較兩個(gè)數(shù)據(jù)對(duì)象是否相同逛犹,可以調(diào)用isEqualToData:方法端辱,這個(gè)方法提供逐個(gè)字節(jié)的比較。
拷貝數(shù)據(jù)對(duì)象
開發(fā)者可以以拷貝的方式來創(chuàng)建一個(gè)只讀的或者可修改的數(shù)據(jù)對(duì)象虽画。NSData和NSMutableData實(shí)現(xiàn)了NSCopying協(xié)議以及NSMutableCopying協(xié)議舞蔽,這就確保了可以在支隊(duì)對(duì)象和可修改對(duì)象之間進(jìn)行方便的轉(zhuǎn)換。開發(fā)者可以通過調(diào)用copy方法來創(chuàng)建只讀的拷貝码撰,也可以通過mutableCopy來創(chuàng)建可修改的拷貝渗柿。
存儲(chǔ)數(shù)據(jù)對(duì)象
開發(fā)者可以將字節(jié)數(shù)據(jù)存儲(chǔ)在本地文件或者互聯(lián)網(wǎng)中。writeToFile:atomically:方法以及writeToURL:atomically:方法可以讓開發(fā)者將字節(jié)數(shù)據(jù)保存在本地文件中脖岛。
使用可變二進(jìn)制數(shù)據(jù)
本節(jié)包含了一些和可變數(shù)據(jù)對(duì)象(也就是NSMutableData)有關(guān)的代碼示例做祝。開發(fā)者可以通過直接修改字節(jié)數(shù)組砾省、添加新數(shù)據(jù)以及替換指定范圍內(nèi)的數(shù)據(jù)這些方式來改變可修改數(shù)據(jù)對(duì)象。
修改字節(jié)
NSMutableData的兩個(gè)方法mutableBytes以及setLength:為本類的其他方法提供了基礎(chǔ)混槐。其中编兄,mutableBytes返回的是一個(gè)指向可修改字節(jié)數(shù)據(jù)的指針。而setLength:方法允許開發(fā)者對(duì)數(shù)據(jù)對(duì)象中的緩沖字節(jié)進(jìn)行范圍擴(kuò)展或者截?cái)嗌恰ncreaseLengthBy:方法同樣可以讓開發(fā)者改變可修改數(shù)據(jù)對(duì)象中的數(shù)據(jù)長度狠鸳。
在下面代碼段中,mutableBytes可以返回一個(gè)指向data2的指針悯嗓。然后使用data1的數(shù)據(jù)覆蓋data2的數(shù)據(jù)件舵。
代碼段1,修改字節(jié)
NSMutableData *data1, *data2;
NSString *myString = @"string for data1";
NSString *yourString = @"string for data2";
const char *utfMyString = [myString UTF8String];
const char *utfYourString = [yourString UTF8String];
unsigned char *firstBuffer, secondBuffer[20];
/* initialize data1, data2, and secondBuffer... */
data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)+1];
data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)+1];
[data2 getBytes:secondBuffer length:20];
NSLog(@"data2 before: \"%s\"\n", (char *)secondBuffer);
firstBuffer = [data2 mutableBytes];
[data1 getBytes:firstBuffer length:[data2 length]];
NSLog(@"data1: \"%s\"\n", (char *)firstBuffer);
[data2 getBytes:secondBuffer length:20];
NSLog(@"data2 after: \"%s\"\n", (char *)secondBuffer);
下面是代碼段1的輸出:
Oct 3 15:59:51 [1113] data2 before: "string for data2"
Oct 3 15:59:51 [1113] data1: "string for data1"
Oct 3 15:59:51 [1113] data2 after: "string for data1"
添加字節(jié)
appendBytes:length:方法以及appendData:方法可以讓開發(fā)者在可修改數(shù)據(jù)對(duì)象中進(jìn)行數(shù)據(jù)添加脯厨。比如說铅祸,代碼段2就是將data2中的數(shù)據(jù)拷貝到aBuffer中,然后將aBuffer中的數(shù)據(jù)添加到data1中
NSMutableData *data1, *data2;
NSString *firstString = @"ABCD";
NSString *secondString = @"EFGH";
const char *utfFirstString = [firstString UTF8String];
const char *utfSecondString = [secondString UTF8String];
unsigned char *aBuffer;
unsigned len;
data1 = [NSMutableData dataWithBytes:utfFirstString length:strlen(utfFirstString)];
data2 = [NSMutableData dataWithBytes:utfSecondString length:strlen(utfSecondString)];
len = [data2 length];
aBuffer = malloc(len);
[data2 getBytes:aBuffer length:[data2 length]];
[data1 appendBytes:aBuffer length:len];
程序的輸出為ASCII的字符數(shù)組“ABCDEFGH”
替換字節(jié)
開發(fā)者可以通過方法resetBytesInRange:或者使用replaceBytesInRange:withBytes方法來將可修改數(shù)據(jù)對(duì)象中的指定范圍的字節(jié)重置為0合武。在代碼段3中临梗,data1中的指定范圍的數(shù)據(jù)被data2中的數(shù)據(jù)替代了,然后data1中的數(shù)據(jù)就從”Liz and John”變成了”Liz and Larry”稼跳。
NSMutableData *data1, *data2;
NSString *myString = @"Liz and John";
NSString *yourString = @"Larry";
const char *utfMyString = [myString UTF8String];
const char *utfYourString = [yourString UTF8String];
unsigned len;
unsigned char *aBuffer;
NSRange range = {8, strlen(utfYourString)};
data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)];
data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)];
len = [data2 length];
aBuffer = malloc(len);
[data2 getBytes:aBuffer length:len];
[data1 replaceBytesInRange:range withBytes:aBuffer];