iOS 统一类型标识符概述

前言

最近公司的活比较少,空闲时间十分多,遍寻思着写一款APP。在这个过程中便有使用到统一类型标识符,于是翻译了这个文档。

原文地址

目前写的这个是本地阅读软件,后续会把在写这个APP用到的技术以及遇到的问题都整理出来,通过博客的形式分享给大家。

奇迹读书地址

简介

应用程序开发人员面临的挑战之一是用于识别数据类型的方法的激增。例如,一些文本文件可能被分配为“TEXT”文件类型(最初为Mac OS 9及更早版本设计),而其他文本文件可能只是有一个.txt扩展名。有些可能使用.text扩展名。此外,一些文件类型可能是其他类型的子集;打开所有.txt文件的应用程序应该也能够打开那些扩展名为.html的文件。确定应用程序可以读取的所有可能文件是不可能的。用户体验因此受到影响,用户不理解为什么应用程序可以打开一个文本文件而不能打开另一个文本文件。

为了解决这个问题,Apple为特殊的数据标识符定义了一种语法,称为统一类型标识符。每个UTI都为特定的文件类型、数据类型、目录或包类型等提供了唯一标识符。此外,可以将特定类型的其他类型标识符名称空间分组在一个UTI下,并使用实用的函数将一种格式转换为另一种格式。

OS X和iOS应用程序开发人员,他们需要创建或操作可能与其他应用程序或服务交换的数据。例如,应用程序通常需要知道它们处理的数据类型:

  • 显示或操作文件、包或文件夹
  • 访问流数据
  • 在文档或应用程序之间复制和粘贴
  • 在应用程序之间拖放

OS X v10.3及更高版本和iOS 3.0及更高版本支持统一类型标识符。

统一类型标识符(UTIs)提供了一种统一的方式来标识系统中处理的数据,例如文档、粘贴板数据和包。本章描述了uti背后的概念,并展示了如何在应用程序包中指定它们。

什么是统一类型标识符?

统一类型标识符是唯一标识被认为具有“类型”的一类实体的字符串。例如,对于一个文件或其他字节流,“类型”指的是数据的格式。对于包和包之类的实体,“类型”指的是目录层次结构的内部结构。最常见的是,UTI为所有应用程序和服务都可以识别和依赖的数据提供一致的标识符,从而消除了跟踪所有现有标记数据方法的需要。例如,目前,一个JPEG文件可以通过以下任何一种方法识别:

  • four-character文件类型代码(OSType)为'JPEG'
  • 文件扩展名为.jpg
  • 文件扩展名为.jpeg
  • MIME type类型为image/jpeg

UTI用字符串public.jpeg替换所有这些不兼容的标记方法。这个字符串标识符与任何旧的标记方法完全兼容,可以调用实用程序函数将一种方法转换为另一种方法。也就是说,对于给定的UTI,可以生成等效的OSType、MIME type或文件名扩展名,反之亦然。

因为uti可以识别任何类型的实体,所以它们比旧的标记方法灵活得多; 还可以使用它们来标识以下任何实体:

  • 粘贴板数据
  • 文件夹(目录)
  • 框架
  • 流数据
  • 别名和符号链接

此外,可以为特定于应用程序的用途定义自己的uti。例如,如果应用程序使用一种特殊的文档格式,可以为它声明一个UTI。希望支持此格式的第三方应用程序或插件可以使用该UTI来标识此类文件。

UTI字符集

统一类型标识符是一个Unicode字符串,通常包含ASCII字符集中的字符。但是,只允许使用ASCII字符的子集。你可以使用大写和小写的罗马字母(A-Z, A-Z),数字0到9,点(" . ")和连字符(" - ")。此限制基于RFC 1035中规定的DNS名称限制。

统一类型标识符也可以包含大于U+007F的任何Unicode字符。

重要提示:UTI字符串中出现的任何非法字符——例如,下划线(“_”)、冒号(“:”)或空格(“ ”)——将导致该字符串作为无效UTI被拒绝。在API层,不会为无效的uti生成错误。

UTI语法

统一类型标识符使用反向dns格式,最初用于描述Java类层次结构的元素,现在也用于OS X和iOS中的包标识。一些例子:

com.apple.quicktime-movie
com.mycompany.myapp.myspecialfiletype
public.html
com.apple.pict
public.jpeg

UTI语法确保给定的标识符是唯一的,而不需要中央机构注册或以其他方式跟踪它们。请注意,域(com、public等)仅用于标识UTIs在域层次结构中的位置;它并不意味着任何类似类型的分组。

  • public域是为大多数应用程序普遍使用的普通或标准类型保留的:
public.text
public.plain-text
public.jpeg
public.html

具有公共域的UTIs称为公共标识符。目前只有苹果可以声明公共标识符。

  • dyn域为特殊的动态标识符保留。有关更多信息,请参阅动态类型标识符。
  • 所有其他域名均可由第三方使用。通常,公司声明的标识符将以com域开始。
com.apple.quicktime-movie
com.yoyodyne.buckybits

一致性

统一类型标识符相对于其他类型标识方法的一个关键优势是,它们是在一致性层次结构中声明的。一致性层次结构类似于面向对象编程中的类层次结构。除了“类型A符合类型B”,还可以将其视为“类型A的所有实例也是类型B的实例”。

图1-1显示了一些统一类型标识符的一致性层次结构。

图1-1一致性层次结构

conformance_hierarchy.gif

例如,定义HTML文本的UTI public.html符合基本文本标识符public.text。在这种情况下,一致性让可以打开一般文本文件的应用程序将HTML文件识别为它也可以打开的文件。

只需要用类型的直接“超类”声明一致性,因为一致性层次结构允许标识符之间的继承。也就是说,如果将标识符声明为符合public.tiff标识符,那么它将自动符合层次结构中较高层的标识符,例如public.image和public.data。

一致性层次结构支持多重继承。例如,应用程序包(com.apple.application-package)的UTI既符合通用包类型(com.apple.bundle),也符合打包目录类型(com.apple.package)。

在为UTI指定一致性时,理想情况下应该同时符合物理和功能层次结构。也就是说,一致性应该指定它的物理性质(目录、文件等)以及它的用途(图像、电影等)。

  • 物理层次结构中的UTI应该遵循继承层次结构中的public.item。
  • 功能层次结构中的UTI应该通过继承与非public.item的基UTI保持一致。例如,public.content,public.executable和public.archive都是功能基UTIs的例子。

虽然遵循功能层次结构不是强制性的,但这样做可以更好地与系统特性集成。例如,Spotlight将命名属性(标题、作者、版本、注释等等)与功能UTIs关联起来。

图1-2显示了物理和功能层次结构的示例:

图1-2物理结构和功能结构

physical_vs_functional.gif

在某些情况下,只需要声明对一个UTI的一致性覆盖两个层次结构。例如,public.text、public.image和public.audiovisual-content既符合public.data(物理)和public.content(功能),因此符合(直接或间接)其中一个项涵盖了两个层次结构。

一致性使应用程序在确定与哪些类型兼容时更加灵活;这样不仅可以避免编写大量的条件代码,而且应用程序还可以与从未预料到的类型兼容。

动态类型标识符

有时可能会遇到没有声明UTI的数据类型。UTIs通过为该类型创建动态标识符来透明地处理这种情况。例如,假设应用程序发现了一个它无法识别的NSPasteboard类型。使用实用函数,它仍然可以将类型转换为可以传递的UTI。

动态标识符具有域dyn,后面的字符串的其余部分是不透明的。可以像处理任何其他UTI一样处理动态标识符,并且可以使用实用函数提取原始标识符标记。可以将动态标识符视为围绕未知的文件名扩展名、MIME type、OSType等的与UTI兼容的包装器。

标识符标记

每个UTI可以有一个或多个与之关联的标记。这些标记指示类型识别的替代方法,例如文件名扩展名、MIME type或NSPasteboard类型。可以使用这些标记来分配特定的扩展、MIME type等,作为UTI声明中的等效类型。

例如,public.jpeg标识符声明包括一个OSType标记('JPEG')和两个文件名扩展标记(.jpg和.jpeg)。然后,这些标记被视为public.jpeg类型的替代标识符。

从本质上讲,可以使用标记将所有可能用于在一个UTI下识别类型的方法分组。也就是说,扩展名为.jpg或.JPEG的文件,或OSType为'JPEG'的文件都被认为是public.jpeg类型的文件。

声明新的UTIs

Mac应用程序可以为自己的专有格式声明新的UTIs。在包的信息属性列表中声明新的uti。有关更多信息,请参见声明新的统一类型标识符。

采用统一类型标识符

本章给出了在应用程序中采用统一类型标识符的一些指导原则,并概述了用于操作uti的实用函数。

UTI使用指南

在应用程序中采用UTIs分为两部分。应该在需要标识或交换数据时使用UTIs,并且应该为应用程序使用的任何专有类型声明特定的UTIs。

为OS X应用程序添加UTI支持

苹果在整个OS x中使用UTIs。例如:为大多数数据交换需求构建UTI支持。例如,以下技术都支持uti:

  • Pasteboard Manager和Translation Services使用UTIs来标识数据类型。
  • 导航服务允许指定用于文件过滤的UTIs。
  • Launch Services支持基于UTI的文档声明。
  • NSView和NSWindow支持基于UTI的拖放协议。
  • NSDocument、NSOpenPanel、NSSavePanel和NSWorkspace都支持UTIs。
  • NSSound, NSImage和NSImageRep使用UTIs返回支持的数据格式。

此外,Apple已经弃用了大多数用于识别数据的旧机制,转而支持UTIs。

如果有上述未解决的特定需求,可以在自己的代码中将类型与UTIs匹配。通常,这需要找到具有替代标识符(例如OSType)的类型,从该标识符创建UTI,然后检查UTI是否符合定义应用程序可以处理的类型的UTI。有关如何做到这一点的示例,请参见导航服务编程指南中的导航服务任务

重要提示:在代码中使用系统定义的UTIs时,应该使用Launch Services框架中UTCoreTypes.h中定义的常量,而不是实际的UTI字符串。例如,传kUTTypeApplication而不是"com.apple.application"。系统声明的统一类型标识符除了UTI字符串之外还列出了这些常量。

为iOS应用程序添加UTI支持

iOS应用程序使用UTIs来表示粘贴板类型。有关更多信息,请参见UIPasteboard类参考

重要提示:在代码中使用系统定义的UTIs时,应该使用MobileCoreServices框架中UTCoreTypes.h中定义的常量,而不是实际的UTI字符串。例如,传递kUTTypeApplication而不是"com.apple.application"。系统声明的统一类型标识符除了UTI字符串之外还列出了这些常量。

UTI函数概述

可以在OS X的Launch Services框架和iOS的MobileCoreServices框架中找到UTType.h中用于操作UTIs的函数。

相等性和一致性测试

当测试两个UTIs是否相同时,应该总是使用UTTypeEqual函数,而不是直接比较字符串:

Boolean UTTypeEqual (
        CFStringRef inUTI1,
        CFStringRef inUTI2
    );

这两个UTIs是相等的:

  • UTI字符串是相同的
  • 动态标识符的标记规范是其他UTI的标记规范的子集。

然而,在许多情况下,希望确定一个UTI是否与另一个UTI兼容,在这种情况下,应该检查一致性而不是相等性:

Boolean UTTypeConformsTo (
        CFStringRef inUTI1,
        CFStringRef inUTI2
    );

如果inUTI1符合inUTI2, UTTypeConformsTo函数返回true。一致性关系是可传导的:如果A符合B, B符合C,那么A符合C。

操纵标签

通常为了有效地使用UTIs,必须能够将各种其他类型标识符(OSType、MIME等)转换为UTIs,反之亦然。

要将标识符转换为UTI,可以使用UTTypeCreatePreferredIdentifierForTag函数:

CFStringRef UTTypeCreatePreferredIdentifierForTag(
        CFStringRef inTagClass,
        CFStringRef inTag,
        CFStringRef inConformingToUTI
    );

对于标记类,传递下列定义替代标识符的标记类常量之一:

const CFStringRef kUTTagClassFilenameExtension;
const CFStringRef kUTTagClassMIMEType;
const CFStringRef kUTTagClassNSPboardType;
const CFStringRef kUTTagClassOSType;

可以在inConformingToUTI参数中传递一个UTI作为提示,以防给定的标记出现在多个UTI声明中。例如,如果知道文件名扩展名标记与文件关联,而不是与目录关联,则可以传递public.data。这将导致函数忽略具有相同扩展名且符合public.directory的任何类型。如果没有提示,则为该参数传递NULL。

在存在两个或多个具有相同标识符的类型的罕见情况下,该函数更倾向于使用公共UTIs。如果标识符不存在声明的UTI, UTTypeCreatePreferredIdentifierForTag将创建并返回一个动态标识符。

如果想获得与给定标识符对应的所有UTIs,可以调用UTTypeCreateAllIdentifiersForTag:

CFArrayRef UTTypeCreateAllIdentifiersForTag(
    CFStringRef inTagClass,
    CFStringRef inTag,
    CFStringRef inConformingToUTI );

这个函数返回一个UTIs数组,可以通过检查这些数组来确定使用哪个UTI。

如果想从UTI创建一个替代标识符,调用UTTypeCopyPreferredTagWithClass函数:

CFStringRef UTTypeCopyPreferredTagWithClass(
    CFStringRef inUTI,
    CFStringRef inTagClass );

首选标记是给定标记类的标记规范数组中列出的第一个标记。

转换OSType标识符

UTI实用函数假定所有替代标识符标记都可以表示为Core Foundation字符串。然而,由于OSType类型是基于整数而不是基于字符串的,因此如何在CFStringRef类型和OSType类型之间正确转换可能并不明显。为了确保OSType标识符的无错误编码和解码,可以使用以下转换函数:

CFStringRef UTCreateStringForOSType( OSType inOSType );
 
OSType UTGetOSTypeFromString( CFStringRef inTag );

注意:对于只包含可打印的7位ASCII字符的OSType值,仍然可以使用CFSTR宏和一个四字符字符串文字(例如,CFSTR(“TEXT”))来创建一个有效的OSType标记。

访问UTI信息

要获得UTI声明的副本,使用UTTCopyDeclaration函数:

CFDictionaryRef UTTypeCopyDeclaration(
    CFStringRef inUTI );

使用UTTypeCopyDeclaringBundleURL函数获取包含给定UTI声明的bundle的URL:

CFURLRef UTTypeCopyDeclaringBundleURL(
    CFStringRef inUTI );

要获得给定UTI的本地化描述,请调用UTTypeCopyDescription函数:

CFStringRef UTTypeCopyDescription(
    CFStringRef inUTI );

声明新的统一类型标识符

Mac应用程序可以为专有数据格式添加新的统一类型标识符。在包的信息属性列表(info.plist)文件中声明新的UTIs。可以在以下任何一种情况下声明新的uti:

  • 应用程序包
  • 进口商捆绑包
  • 自动动作包

申明UTIs

除了声明UTI字符串外,声明还可以包含以下任何属性:

  • 类型的标记规范,指定与此类型匹配的所有替代标识符标记
  • 此标识符符合的UTIs列表
  • 显示此类型项时使用的图标
  • 描述此标识符的用户可读字符串,包含该标识符的bundle可以对其进行本地化

UTI声明必须导入或导出:

  • 导出的UTI声明意味着该类型可供所有其他方使用。例如,使用专有文档格式的应用程序应该将其声明为导出的UTI。
  • 导入的UTI声明用于声明包不拥有的类型,但希望在系统中看到该类型可用。例如,假设一个视频编辑程序使用专有格式创建文件,其UTI在其应用程序包中声明。如果正在编写可以读取此类文件的应用程序或插件,则必须确保系统知道专有UTI,即使实际的视频编辑应用程序不可用。为此,应用程序应该在自己的包中重新声明UTI,但将其标记为导入声明。

如果一个UTI同时存在导入和导出声明,则导出声明优先于导入声明。

下面是一个public.jpeg UTI的示例声明,定义为一个导出类型,就像在属性列表中看到的那样:

<key>UTExportedTypeDeclarations</key>
        <array>
            <dict>
                <key>UTTypeIdentifier</key>
                <string>public.jpeg</string>
                <key>UTTypeReferenceURL</key>
                <string>http://www.w3.org/Graphics/JPEG/</string>
                <key>UTTypeDescription</key>
                <string>JPEG image</string>
                <key>UTTypeIconFile</key>
                <string>public.jpeg.icns</string>
                <key>UTTypeConformsTo</key>
                <array>
                    <string>public.image</string>
                    <string>public.data</string>
                </array>
                <key>UTTypeTagSpecification</key>
                <dict>
                    <key>com.apple.ostype</key>
                    <string>JPEG</string>
                    <key>public.filename-extension</key>
                    <array>
                        <string>jpeg</string>
                        <string>jpg</string>
                    </array>
                    <key>public.mime-type</key>
                    <string>image/jpeg</string>
                </dict>
            </dict>
        </array>

表3-1显示了UTI声明中可用的属性键列表。

表3-1统一类型标识符的属性列表键

值类型 描述
UTExportedTypeDeclarations 字典类型的数组 一个导出的UTI声明数组(即包的发布者拥有的标识符)。
UTImportedTypeDeclarations 字典类型的数组 导入的UTI声明数组(即由另一个公司或组织拥有的标识符)。
UTTypeIdentifier 字符串 声明的UTI类型。这个键是UTI声明所必需的。
UTTypeTagSpecification 字典 定义一个或多个等效类型标识符的字典。
UTTypeConformsTo 字符串类型字典 这个标识符所符合的UTIs。
UTTypeIconFile 字符串 与此UTI关联的包图标资源的名称。
UTTypeDescription 字符串 这种类型的用户可见的描述。可以通过在InfoPlist中包含该字符串来本地化该字符串。字符串文件。
UTTypeReferenceURL 字符串 描述此类型的引用文档的URL。

声明新的统一类型标识符的建议

如果应用程序使用专有数据格式,应该在应用程序包的Info.plist文件中声明它们。为了获得最佳效果,请遵循以下指导方针:

  • UTI字符串必须是唯一的。遵循以com.companyName开头的反向dns格式是确保惟一性的简单方法。虽然系统可以支持具有相同规格的不同UTI字符串,但反之则不然。
  • 如果代码依赖于系统中可能不存在的第三方UTI类型,那么应该将这些UTI声明为包中的导入类型。
  • 如果专有类型是一个或多个现有类型的子类型,请确保添加一致性信息。在大多数情况下,不应该指定与非公共类型的一致性,除非也在包中声明该类型。虽然自定义UTI可以符合任何UTI,但公共public.data或com.apple.package必须位于所有文件格式(如文档)的自定义UTIs的一致性层次结构的根部;否则,系统无法判断磁盘上的项是否具有该UTI。有关公共和apple定义的UTIs列表,请参见系统声明的统一类型标识符

后记

最后再分享一遍这个APP:

奇迹读书地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容