跟着苹果API学习NSData

作者两年iOS开发经验,通过阅读苹果api重温各个知识点,如果你喜欢这个系列,请关注我。有任何建议请留言。转载请注明来源。
本来这个系列只是单纯的苹果api学习笔记,后来想学习一下YYKit的源码,所以在文章中一并加入

作者:Roger


1. Creating Data Objcets[创建Data对象]

首先来看苹果提供给我们创建Data对象的其中三个方法

//创建并返回一个空data对象
+ data

- initWithData:

//根据length大小,创建并返回一个限定字节的data对象
+ dataWithBytes:length:



实验了一下不同情况下NSData的输出结果:
1.如果创建一个空的data,输出的结果也都为空。

NSData *data1 = [NSData data];
NSLog(@"%@,%ld,%@",data1,data1.length,data1.description);
//输出结果: <>,0,<>

NSString *str1 = [[NSString alloc]initWithData:data1 encoding:NSUTF8StringEncoding];
NSLog(@"%@",str1);
//输出结果:



2.通过dataWithBytes:length:创建data,并且data的length等于内容的大小。
*为什么用NSASCIIStringEncoding时,输出中文会得到乱码?
*ASCII,Unicode和UTF-8的区别

const char *string = "Hi there ,this is a C string我了个去";
NSData *data2 = [NSData dataWithBytes:string length:strlen(string)];
NSLog(@"%@,%ld,%@",data2,data2.length,data2.description);
//输出结果:<48692074 68657265 202c7468 69732069 73206120 43207374 72696e67 e68891e4 ba86e4b8 aae58ebb>,40,<48692074 68657265 202c7468 69732069 73206120 43207374 72696e67 e68891e4 ba86e4b8 aae58ebb>    

//utf8和ascii区别?
NSString *str2 = [[NSString alloc]initWithData:data2 encoding:NSUTF8StringEncoding];
NSString *str22 = [[NSString alloc]initWithData:data2 encoding:NSASCIIStringEncoding];
NSLog(@"str2 = %@,str11 = %@",str2,str22);
//输出结果:str2 = Hi there ,this is a C string****我了个去****,str11 = Hi there ,this is a C stringæ��äº�个å�»



3.通过dataWithBytes:length:创建data,并且data的length小于内容的大小。可以发现,如果length小于data的实际大小,输出的结果为空。

NSData *data3 = [NSData dataWithBytes:string length:strlen(string - 1)];
NSLog(@"%@,%ld,%@",data3,data3.length,data3.description);
//输出结果: <>,0,<>
NSString *str3 = [[NSString alloc]initWithData:data3 encoding:NSUTF8StringEncoding];
NSLog(@"str3 = %@",str3);
//输出结果:str3 =



3.通过dataWithBytes:length:创建data,并且data的length大于内容的大小。如果length大于data的实际大小,大于多少位,输出的字符就缺少多少位。

NSData *data4 = [NSData dataWithBytes:string length:strlen(string + 5)];
NSLog(@"%@,%ld,%@",data4,data4.length,data4.description);
//输出结果:<48692074 68657265 202c7468 69732069 73206120 43207374 72696e67 e68891e4 ba86e4b8 aae58ebb>,40,<48692074 68657265 202c7468 69732069 73206120 43207374 72696e67 e68891e4 ba86e4>    

 NSString *str4 = [[NSString alloc]initWithData:data4 encoding:NSUTF8StringEncoding];
    NSLog(@"str4 = %@",str4);
//输出结果:str4 = nil

总结:

  1. 如果通过方法dataWithBytes:length:创建data时,length的大小小于实际内容大小时,会创建一个byte为0的data对象。通过data转string,输出为空。
  2. 如果length的大小大于实际内容大小时,大于多少位,输出data的字符就缺少多少位。通过data转string,输出为nil。



接着我们再来看另外两个创建Data对象的方法:

+ dataWithBytesNoCopy:length:

+ dataWithBytesNoCopy:length:freeWhenDone:

在使用dataWithBytesNoCopy:length:创建data对象时,会有崩溃发生:

malloc: *** error for object 0x10f344665: pointer being freed was not allocated**
***** set a breakpoint in malloc_error_break to debug

大概搜索了一下原因,对这里的了解似懂非懂,暂留坑,总之在没搞清楚这里的情况下,最好按照下面的回答说的,使用dataWithBytes来创建data对象。

跟着苹果API学习NSData_第1张图片
屏幕快照 2016-08-31 下午3.05.14.png




两个通过地址创建data对象的方法:

//根据地址创建data对象
+ dataWithContentsOfFile:

//根据地址创建data对象,并根据枚举类型操作data
+ dataWithContentsOfFile:options:error:

typedef NS_OPTIONS(NSUInteger, NSDataReadingOptions) {
    //使用这个参数后,iOS就不会把整个文件全部读取的内存了,而是将文件映射到进程的地址空间中。
    //这么做并不会占用实际内存。这样就可以解决内存满的问题。
    NSDataReadingMappedIfSafe = 1UL << 0,
    //数据将不会存入内存中,对于只会使用一次的数据,这么做会提高性能。
    NSDataReadingUncached = 1UL << 1,
    //数据始终会被存储在内存中,如果用户定义了NSDataReadingMappedIfSafe和这个枚举,那么这个枚举会优先起作用。
    NSDataReadingMappedAlways NS_ENUM_AVAILABLE(10_7, 5_0) = 1UL << 3, 
    
    //老枚举,苹果建议不再使用。
    NSDataReadingMapped = NSDataReadingMappedIfSafe, // Deprecated name for NSDataReadingMappedIfSafe
    NSMappedRead = NSDataReadingMapped,   // Deprecated name for NSDataReadingMapped
    NSUncachedRead = NSDataReadingUncached  // Deprecated name for NSDataReadingUncached
};

类似上面的方法,还有通过url创建data对象的方法,在视频播放方面会用到这个方法

- initWithContentsOfURL:

- initWithContentsOfURL:options:error:

2. Accessing Data[访问Data对象]

  • bytes

    属性,如果Data的length为0,此方法返回nil。

  • description

属性,一个十六进制字符串,包含在属性列表格式的对象的内容表示。(只读)

  • -enumeraterByteRangesUsingBlock:
    NSData 对象如果是由许多不同的对象组合而成,因此可以使用 NSData 的 enumerateByteRangesUsingBlock: 来遍历数据。
  • -getBytes:
  • -getBytes:length:
  • -getBytes:range:

接收数据,复制所给范围内字节到一个给定的缓冲区中。

  • -subdataWithRange:

    返回包含在给定范围内的数据对象。

  • -rangeOfData:options:range:

在给定的范围内,以给定的选项,查找并返回给定数据的第一个发生的范围。

3. Base-64 Encoding

填坑...

Testing Data

  • -isEqualToData:
    对比data

*##### length
属性,data的数量

4. Storing Data

  • -writeToFile:atomically:

将接收到的字节写入给定路径指定的文件。
atomically这个参数意思是,如果为YES则保证文件的写入原子性,就是说会先创建一个临时文件,直到文件内容写入成功再导入到目标文件里。 如果为NO,则直接写入目标文件里。

  • -writeToFile:options:error:
typedef NS_OPTIONS(NSUInteger, NSDataWritingOptions) {
    //等同于上面的atomically == YES
    NSDataWritingAtomic = 1UL << 0, 
    //如果已存在文件,则不会覆盖原文件,写入失败。
    NSDataWritingWithoutOverwriting NS_ENUM_AVAILABLE(10_8, 6_0) = 1UL << 1, 
    //資源沒有與其相關聯的特殊保護。任何時候都可以讀取或寫入資源
    NSDataWritingFileProtectionNone NS_ENUM_AVAILABLE_IOS(4_0)                                  = 0x10000000,
    //資源會以加密格式儲存在磁碟,當裝置處於鎖定狀態或者正在開機時,將無法進行讀取或寫入。
    NSDataWritingFileProtectionComplete NS_ENUM_AVAILABLE_IOS(4_0)                              = 0x20000000,
    //資源會以加密格式儲存在磁碟。當裝置處於鎖定狀態時,可以建立資源,但是一旦關閉資源,就無法再次開啟,直到裝置解除鎖定。如果在解除鎖定時開啟了資源,則可以如常繼續存取資源,即使使用者鎖定了裝置也無妨。
    NSDataWritingFileProtectionCompleteUnlessOpen NS_ENUM_AVAILABLE_IOS(5_0)                    = 0x30000000,
    //資源會以加密格式儲存在磁碟,只有在裝置開機之後,才能存取資源。在使用者首次解除鎖定裝置之後,您的應用程式可以存取資源,即使使用者之後鎖定了裝置,還是可以繼續存取。
    NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication NS_ENUM_AVAILABLE_IOS(5_0)  = 0x40000000,
    NSDataWritingFileProtectionMask NS_ENUM_AVAILABLE_IOS(4_0)                                  = 0xf0000000,

    //不建议再使用
    NSAtomicWrite = NSDataWritingAtomic     // Deprecated name for NSDataWritingAtomic
};
  • -writeToUrl:atomically:

填坑...

  • -writeToUrl:options:error:

填坑...

你可能感兴趣的:(跟着苹果API学习NSData)