作者两年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
总结:
- 如果通过方法
dataWithBytes:length:
创建data时,length的大小小于实际内容大小时,会创建一个byte为0的data对象。通过data转string,输出为空。 - 如果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对象。
`
两个通过地址创建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:
填坑...