HRCoder 是 NSKeyedArchiver 和 NSKeyedUnarchiver 类的替代品。虽然 NSKeyedArchiver 按标准 Plist 格式写入数据,但 Plist 的结构使得阅读变得困难,几乎无法手动生成。
HR 代表 Human Readable(可读性)。HRCoder 用比 NSKeyedArchiver 简单的格式保存文件;标准对象(如字符串、字典、数组、数字、布尔值和二进制数据)都使用标准的 Plist 原语进行保存和加载,其他任何类型的对象都保存为一个简单的字典,并添加一个 $class 键来表示对象类型。
这使得手动生成与 HRCoder 兼容的 Plist 文件变得简单,然后可以使用标准的 NSCoding 协议进行加载。您还可以安全地读取和手动编辑由 HRCoder 类保存的文件,而不用担心文件损坏。
HRCoding 使用的简单字典/数组格式也可以轻松存储为 JSON,从而为序列化提供了更多选项(NSKeyedArchiver 与 Plists 相关联,不能轻易用于保存为 JSON,除非作为中间步骤创建 Plist)。
HRCoder 设计与 AutoCoding 库(https://github.com/nicklockwood/AutoCoding)一起工作,该库可以自动为您的类写入 initWithCoder:
和 encodeWithCoder:
方法。查看 AutoTodoList 示例以了解其工作原理。
HRCoder 还旨在与 BaseModel 库(https://github.com/nicklockwood/BaseModel)紧密协作,该库可以以最小的工作量为基础构建一个强大的模型层次结构。查看 BaseModel 仓库中包含的 HRTodoList 示例,了解这些库如何协同工作。
注意:'支持' 意味着该库已为此版本进行测试。'兼容' 意味着该库应该在该 OS 版本上运行(即它不依赖于任何不可用的 SDK 特性),但不再测试兼容性,可能需要调整或错误修复才能正确运行。
截至版本 1.3,HRCoder 需要 ARC。如果您希望在非 ARC 项目中使用 HRCoder,只需将 -fobjc-arc 编译器标志添加到 HRCoder.m 类文件中。为此,请转到目标设置中的编译阶段标签,打开编译源代码组,在列表中双击 HRCoder.m 并在弹出窗口中输入 -fobjc-arc。
如果您想将整个项目转换为ARC,请注释掉HRCoder.m中的#error行,然后在Xcode中选择Edit > Refactor > Convert to Objective-C ARC...工具,并确保您希望使用ARC的所有文件都勾选(包括HRCoder.m)。
从多个线程并发访问单个HRCoder实例是不安全的,但使用HRCoder类的方法进行编码和解码对象是完全线程安全的。
要使用HRCoder,只需将HRCoder.h和.m文件拖动到您的项目中。
@property (nonatomic, assign) HRCoderFormat outputFormat;
此属性可用于设置序列化HRCoded对象的输出格式。可能的值有HRCoderFormatXML
、HRCoderFormatJSON
和HRCoderFormatBinary
。默认值是HRCoderFormatXML
,它会产生一个XML Plist。
HRCoder实现了以下方法,这些方法与NSKeyedArchiver和NSKeyedUnarchiver类的那些方法相匹配。
+ (id)unarchiveObjectWithPlistOrJSON:(id)plistOrJSON;
从编码的Plist或JSON对象构造一个对象树,并返回它。plistOrJSON参数可以是Plist或JSON格式本机支持的任何对象。这通常是一个容器对象,如NSDictionary或NSArray。如果提供了其他类型的对象,则将返回未修改的对象。
请注意,此对象实际上不一定是加载自Plist或JSON文件,您可以按编程方式创建这样一个对象。
+ (id)unarchiveObjectWithData:(NSData *)data;
从NSData对象加载序列化的plist,并通过在文件中的根对象上调用unarchiveObjectWithPlist:
来返回一个未归档的对象树。支持文本、JSON、XML或二进制格式化的数据。使用可变容器解序列化数据以确保归档数组和字典的可变性。如果您更喜欢不可变对象,则可以直接使用NSPropertyListSerialization
或NSJSONSerialization
类加载对象。
+ (id)unarchiveObjectWithFile:(NSString *)path;
加载Plist格式的数据文件,并通过在文件中调用unarchiveObjectWithData:
来返回一个未归档的对象树。
+ (id)archivedPlistWithRootObject:(id)object;
将传入的对象编码为与Plist兼容的层次结构,并返回它。结果对象通常将是NSDictionary、NSArray、NSString、NSData、NSDate或NSNumber之一。然后将此对象安全地传递给NSPropertyListSerialisation进行转换为原始数据或保存到文件。
+ (id)archivedJSONWithRootObject:(id)object;
将传入的对象编码为与JSON兼容的层次结构,并返回它。结果对象通常是NSDictionary、NSArray、NSString、NSNumber或NSNull之一。然后将此对象安全地传递给NSPropertyListSerialisation进行转换为原始数据或保存到文件。
+ (NSData *)archivedDataWithRootObject:(id)rootObject;
通过调用archivedPlistWithRootObject:
将传入的对象编码,然后使用XML属性列表格式将其序列化为数据。
+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;
通过调用archivedDataWithRootObject:
将传入的对象编码,然后将它保存到指定的文件路径。文件以原子方式保存以防止数据损坏。
- (id)initForReadingWithData:(NSData *)data;
此方法用于从可以传递给类的initWithCoder:方法的编码NSData对象创建一个HRCoder实例。它主要为了与具有相同方法的NSKeyedUnarchiver
类兼容。数据必须包含一个plist编码的NSDictionary对象。不支持此方法中其他根对象类型(您可以使用unarchiveObjectWithData:
方法加载包含其他根对象类型的数据)。
- (id)initForWritingWithMutableData:(NSMutableData *)data;
此方法用于创建一个用于写入数据对象的 HTCoder 对象。创建 HRCoder 实例后,可以将它传递给对象的 encodeWithCoder:
方法以对其进行编码。编写完对象后,调用 finishEncoding
将序列化的 plist 数据写入 NSMutableData 对象。
- (void)finishDecoding;
使用 initForReadingWithData:
方法打开的数据完成解码。
- (void)finishEncoding;
使用 initForWritingWithMutableData:
方法打开文件后,这将关闭文件并将序列化后的数据写入最初指定的 NSMutableData 对象。
任何普通的 Plist 都可以使用 HECoder 加载,其行为与使用 NSPropertyListSerialization
加载相同。要向 Plist 中添加自定义类,定义对象时将其视为字典,但添加一个额外的 $class
键,指定对象的类名。例如,此代码会生成一个普通的 NSDictionary
<dict>
<key>coming</key>
<string>Hello</string>
<key>going</key>
<string>Goodbye</string>
</dict>
但是这将加载一个 Greetings
类型的对象(假设这个类存在于你的项目中)。
<dict>
<key>$class</key>
<string>Greetings</string>
<key>coming</key>
<string>Hello</string>
<key>going</key>
<string>Goodbye</string>
</dict>
NSCoding 的另一个特性是普通 Plist 不支持的循环引用。HRCoding 使用别名机制支持这
<dict>
<key>$alias</key>
<string>path.to.the.object</string>
</dict>
别名值是原始对象在层次结构中的键路径。为了了解它是如何工作的,这里有一个简单的例子
<dict>
<key>object1</key>
<string>Hello World</string>
<key>object2</key>
<dict>
<key>$alias</key>
<string>object1</string>
</dict>
</dict>
一旦加载,object1 和 object2 属性都将指向同一个 "Hello World" 字符实例(不仅是相同的价值,而且是相同的实际对象)。这也适用于数组 - 只需要使用数组索引作为别名键
<array>
<string>Hello World</string>
<dict>
<key>$alias</key>
<string>0</string>
</dict>
</array>
别名中允许使用前向引用(即对层次结构中稍后声明的对象进行别名化),然而应尽可能避免这样做,因为它涉及到在反序列化对象树时插入 HRCoderAliasPlaceholder
对象,然后在稍后替换这些对象,这会带来轻微的性能损失。
注意,如果你使用别名,你应该小心不要在 initWithCoder:
方法中对反序列化对象调用方法,因为它们可能在加载完成之前不是预期的类型。
版本 1.3.2
版本 1.3.1
版本 1.3
版本 1.2.3
版本 1.2.2
版本 1.2.1
版本 1.2
initForReadingWithData:
和initForWritingWithMutableData:
方法,这些方法提高了与NSKeyedArchiver/Unarchiver类接口的兼容性。版本 1.1.3
版本 1.1.2
版本 1.1.1
awakeAfterUsingCoder:
方法。classForCoder
和replacementObjectForCoder:
方法。版本 1.1
unarchiveObjectWithData:
和archivedDataWithRootObject:
方法版本 1.0