Skip to content

第 3 篇:认识 dd-plist —— 它到底是个什么库

本系列第 3 篇。动手翻译前,必须先搞懂原库解决什么问题。这篇用大白话把 plist 和 dd-plist 讲明白。

一、先搞懂:plist 是什么?

plist = Property List(属性列表),是苹果生态(macOS / iOS)里最常见的配置文件 / 数据存储格式

你可以把它理解成苹果版的 JSON——作用和 JSON、XML 一样,就是存一堆有结构的数据,比如:

  • App 的配置信息(Info.plist,每个 iOS / Mac 应用里都有一个)
  • 用户的偏好设置
  • 一些序列化保存下来的数据

举个直观例子,一个 plist 存的东西大概是这样(先用「人话」表示):

{
  姓名: "张三"
  年龄: 23
  注册时间: 2011-02-13
  照片: <一堆二进制数据>
  爱好: ["篮球", "编程"]
}

二、麻烦的地方:同一份数据有 3 种「写法」

plist 棘手的点在于:同一份数据,可以用三种完全不同的格式存进文件

格式长什么样特点
XML 格式<dict><key>Name</key><string>张三</string>...人能看懂,就是标签啰嗦
Binary 格式bplist00... 一堆二进制乱码机器读,文件小、解析快
ASCII 格式{ Name = "张三"; Age = 23; }老式风格,像简化版 JSON

三种格式表达的是同一份数据,只是「外表」不同。 你打开一个 .plist 文件,可能是这三种里的任意一种。

来看原库 test-files/ 里的真实例子,同一份数据的两种写法:

XML 写法test1.plist):

xml
<dict>
  <key>keyA</key>
  <string>valueA</string>
  <key>keyB</key>
  <string>value&amp;B</string>
</dict>

ASCII 写法test1-ascii.plist):

{
  keyA = valueA;
  keyB = "value&B";
}

看到没?一模一样的数据,两种外表。

三、dd-plist 到底做了什么?

它就是一个 「plist 文件的翻译官 + 搬运工」,主要做三件事:

🔹 事情 1:读(解析 Parse)

把任意格式的 plist 文件读进来,变成程序里能操作的对象

plist 文件(不管哪种格式) ──读──▶ 内存里的对象(NSDictionary 等)

而且它能自动识别格式——看文件开头几个字节:bplist 开头是二进制、< 开头是 XML、{( 开头是 ASCII。

🔹 事情 2:写(生成 Write)

反过来,把内存里的对象输出成任意一种格式:

内存里的对象 ──写──▶ plist 文件(XML / 二进制 / ASCII 任选)

🔹 事情 3:转换(Convert)

把一种格式的文件转成另一种。比如把 XML 的 plist 转成体积更小的二进制 plist:

XML 格式文件 ──转──▶ 二进制格式文件

四、那些 NS 开头的类是做什么的?

这是这个库的数据模型。因为 plist 里有各种数据类型(字符串、数字、日期、数组……),库里就用一个类对应一种类型。NS 是苹果的命名前缀(NeXTSTEP 的缩写):

类名对应数据类型类比 JSON
NSString字符串"张三"
NSNumber数字(整数 / 小数 / 布尔)23 / true
NSDate日期时间
NSData二进制数据(如图片)
NSArray数组 / 列表["a", "b"]
NSDictionary字典 / 键值对{"k": "v"}
NSSet集合(元素不重复)
NSNull空值null
NSObject以上所有类的「共同父类」

所以读一个 plist 文件,最后你拿到的通常是一个 NSDictionary(就像 JSON 解析后拿到一个对象),里面又套着 NSStringNSNumberNSArray 等等,层层嵌套。

五、一段真实代码感受一下

原库 README 里的写入例子(Java),能直观看到「构造对象 → 输出文件」的过程:

java
// 创建根对象(一个字典)
NSDictionary root = new NSDictionary();

NSDictionary person = new NSDictionary();
person.put("Name", "Peter");   // 自动包装成 NSString
person.put("Age", 23);          // 自动包装成 NSNumber

root.put("Person", person);

// 输出成 XML 格式的 plist 文件
XMLPropertyListWriter.write(root, new File("people.plist"));

我们要做的,就是让仓颉也能写出类似这样的代码。

六、一句话总结

dd-plist 就是一个处理苹果 .plist 配置文件的工具库:能读(3 种格式自动识别)、能写(生成 3 种格式)、能互转,并用一套 NS* 类在内存里表示这些数据。

我们的任务,就是把这个「plist 工具库」用仓颉语言重新实现一遍,让仓颉程序也能读写 plist 文件。

七、这一步的收获

  • 搞懂了原库的输入输出:文件 ⇄ NS* 对象 ⇄ 三种格式。
  • 搞懂了 NS* 类的分工:一个类对应一种数据类型,NSObject 是它们的爹。
  • 心里有了一张「地图」,下一步就能规划先翻哪个、后翻哪个了。

下一篇通读源码,规划移植路线 —— 面对 28 个陌生文件、近万行代码,怎么理出翻译顺序和难点。