OS X作为桌面操作系统,大量使用framework来分发共享代码和资源。framework是一个层级目录,包含了共享的资源的单个包package,比如一个动态共享库,nib文件,image文件,localized string 文件,header文件和引用文档。多个app可以同时访问这些资源。系统按需要加载这些资源到内存,共享一份资源的copy给需要的app。
framework也是一个捆绑包,它的内容可以使用Core Foundation Bundle服务或Cocoa NSBundle类来访问。但是,与大多数bundle不同,framework bundle不会作为不透明文件出现在Finder中。 framework bundle是用户可以导航的标准目录。 这使得开发人员可以更轻松地浏览框架内容并查看任何包含的文档和头文件。

framework与static和dynamic  shared library具有相同的用途,即它们提供了可由应用程序调用以执行特定任务的例程库。 例如,Application Kit和Foundation框架为Cocoa类和方法提供了编程接口。 与static-linked libraries和其他类型的动态共享库相比,框架提供了以下优势:

  • Frameworks将相关但独立的资源组合在一起。这个分组方便安装、卸载和定位这些资源。
  • Frameworks比libraries能包含更广泛种类类型的资源。比如,一个 framework能包含任意相关header file和文档。
  • 同一个bundle能包含多个版本的framework,这让向下兼容旧版本程序成为可能。
  • 无论有多少进程正在使用这些资源,在任何给定时间,只有一个框架的只读资源副本在物理内存中驻留。 这种资源共享减少了系统的内存占用量,并有助于提高性能。
注意: Frameworks 不要求提供编程接口,能仅仅只包含资源文件,虽然这种使用并不常见。
Darwin层包含许多 静态和动态库,但是除此之外,大部分OS X的接口被打包为frameworks。某些关键库为几个较小但相关的框架提供方便的分组
,包扩 Carbon,Cocoa,Application Services, and Core Services。这些framework 分组成为umbrella frameworks,他们作为一种技术和实现技术的sub-framework之间的抽象层。
除了使用系统框架,你可以创建你自己的framework,私有的使用他们或者公开给其他开发者。私有framework适用于你想在app中使用的代码模块,但是不想让其他人使用。公开的framework意在被其他开发这使用,经常包含头文件和定义了framework公开接口的文档。
Framework bundle的概念
在OS X中,shared resources使用standard framework和umbrella framework进行打包。 这两种类型的框架都具有相同的基本结构,并且可以包含诸如shared library,nib文件,image文件,strings文件,information property list,文档,头文件等资源。 umbrella framework为标准框架结构添加了小的改进,例如包含其他框架的能力。
framework以bundle结构打包。 framework bundle目录以.framework扩展名结尾,与大多数其他bundle不同,framework bundle作为目录而不是文件呈现给用户。 这种开放性使开发人员可以轻松浏览框架中包含的任何头文件和文档。
Framework bundle的结构
Framework bundles 使用的bundle 结构和app使用的不同。framework 使用的bundle基于早期的bundle 格式,允许多个版本代码和头文件存储在bundle内。这个bundle类型孰知为 versioned bundle。允许旧版本app继续运行,即便是 framework binary文件在不停的发展更新。
系统通过在目录名上使用 .framework 扩展名来标识一个 framework,并且标识 Resources目录
在Framework bundles的顶层。在Resource 目录内部有info.plist 文件,包含了 bundle的标识信息。实际的Resource 目录不必居于bundle的顶层。实际上,OS X附带的系统框架在这个位置上与框架的resource目录有一个符号链接。该链接指向资源目录的当前版本,隐藏在bundle中的某个地方。
Resource 目录的内容和app bundle 类似。本地化资源放入language-specific子目录,使用.lproj扩展名。这些子目录持有 strings, images, sounds和 本地化 界面定义,通过目录表达出来。非本地化信息放在Resource 目录的顶层。

Framework的版本

当在Xcode中构建一个新framework是,构建环境为你自动创建了一个bundle 结构版本。
如下表:
这个图中,Versions目录是bundle在顶层的唯一真实目录。MyFramework和 Resource都是符号连接,连接到 Versions/A里的items。符号连接的原因是:一个Versions/A目录包含实际framework的内容。包含framework的可执行部分和资源。
上图显示了顶层符号链接不直接指向Versions / A目录中的项目。相反,它们指向Versions/Current目录中的项目,它本身是指向Versions / A的符号链接。这种额外的间接级别简化了更改具有多种资源类型的框架的顶层链接以指向框架的特定主要版本的过程,因为只需要更新一个链接Versions/Current版本。
下图显示多个版本的framework

 

通过Versions/Current符号链接,MyFramework.framework / MyFramework指向当前版本的框架Versions/ B / MyFramework的动态共享库。 由于使用符号链接,在程序链接过程中,链接程序会查找框架库的最新版本。 这种安排可确保新程序与最新的主要版本框架相链接,并且随早期主要版本框架构建的程序继续保持不变。 有关使用动态库的更多信息,请参阅Dynamic Library Programming Topics.
重要: 为了让链接器linker找到并链接动态库,框架的名称(不带.framework扩展名)、符号链接、和动态库必须相同。
额外的目录
framework 经常不仅仅包含 Resources 目录。比如,Header,Documentation和Libraries。因此,给上面的例子图片添加一个Headers目录会有下图的结果:
为了在framework中创建额外的目录,您必须将构建阶段(build phases)添加到Xcode中的相应target中。Copy Files build phases能让你创建目录,复制选中文件到这些目录。下表显示常用目录:
Directory Description
Headers
包含你想暴露给外部人员的头文件
Documentation
包含HTML,PDF等描述framework 接口的文件。一般,不会在顶层目录,而是在语言资源文件夹中。
Libraries
包含任意次选的你framework需要的动态库
Framework 配置
Framework需要与任何其他类型的软件包相同的配置。 在Framework的信息属性列表中,您应该包含下图中列出的键。当您在Xcode中设置框架属性时,大多数这些键都会自动包含,但您必须手动添加一些键。
Key Description
CFBundleName The framework display name
CFBundleIdentifier The framework identifier (as a Java-style package name)
CFBundleVersion The framework version
CFBundleExecutable The framework shared library
CFBundleSignature The framework signature
CFBundlePackageType The framework package type (which is always ‘FMWK’)
NSHumanReadableCopyright Copyright information for the framework
CFBundleGetInfoString A descriptive string for the Finder

由于Framework永远不会直接与文档关联,因此您不应指定任何文档类型。如果您愿意,您可以包含显示名称信息。

Umbrella Framework Bundle 结构
Umbrella Framework的结构与标准framework相似,应用程序在链接到Umbrella Framework和标准framework时不区分。 但是,有两个因素将Umbrella Framework与其他framework区分开来。 首先是它们包含头文件的方式。 其次是他们封装子框架的方式。

Umbrella Frameworks的目的

Umbrella Framework目的在于:在特定app环境中,为编程提供所有需要的接口。Umbrella Framework 隐藏了许多不同系统软件之间复杂的相互依赖关系。因此你不需要知道那组frameworks和libraries你必须导入,用以实现特定任务。通过使用预编译的头文件,Umbrella Frameworks也让构建更快。
umbrella framework 简单的包含并且链接了组合的 subframeworks 和其他公开 frameworks。一个umbrella framework 包含所有定义了一个app环境或者系统软件层的技术或者api。它还提供了一层抽象层,让外部开发人员将他们的程序与苹果工程提供的实现相联系。
一个 subframework是一个公开的结构化的framework,打包了指定的Apple 技术,比如Apple events, Quartz,或者Open Transport。然而,一个subframework 是有条件的公开。尽管subframeworks的APIs是公开的,apple 已经加入了某种机制来防止开发者直接连接subframeworks(参考Restrictions on Subframework Linking)。一个subframework 总是存在于一个安装在/System/Library/Frameworks的 umbrella framework,有了它,他的header文件暴露出来。
某些  umbrella framework 包含其他 umbrella frameworks;这是Carbon 和 Cocoa application环境的一种特殊情况。比如,Carbon and Cocoa(直接或间接)导入、连接Core Service umbrella framework(CoreServices.framework)。这个 umbrella framework,这个伞形框架反过来导入和链接诸如Core Foundation等子框架。
在一个 umbrella framework 的 subframeworks的确切组成是一个 会变化的内部实现细节。通过提供一个间接层,umbrella framework 把开发者和这些变化隔离开。Apple 可能 会在一个umbrella framework内重构子框架,并可能在子框架中添加、重命名或删除头文件。如果您将主头文件包含在子框架中,那么这些更改不应该影响您的程序。
The Umbrella Framework Bundle
umbrella frameworks 和 标准Frameworks有相似的结构。一个显著不同是添加了一个Frameworks目录来包含组成umbrella framework的子框架。
下图显示了 Core Services framework的部分列表。 (不包括子框架的内容,因为它们没有被引用。)与标准framework一样,顶层项目是framework目录结构中更深层项目的符号链接。 在这种情况下,链接库和目录位于framework的文件夹A。
与标准framework不同, umbrella frameworks的Headers目录包含一组更加有限的头文件。 它的子框架中不包含标题的集合。 相反,它只包含框架的主头文件。 在源文件中引用 umbrella frameworks 时,应仅包含主头文件。 有关更多信息,请参阅Including Frameworks
Framework 版本
你可以基于动态共享库类型的改变创建不通版本的framework。有两种类型的版本:major(或称为 incompatible不兼容)和 minor (compatible)。两者都对与框架有关的计划产生影响,尽管方式不同。
Major Version
framework的major version也被认为是一个不兼容版本因为她打破了程序连接到前一个版本framework 的动态共享库的兼容性。任何这样的、在这个新版framework下工作的程序会触法运行时错误,因为Framework被改变了。
下面的段落描述你如何在你的framework指定 major version信息、系统如何使用这些信息保证app能运行。

Major Version Numbering Scheme

因为所有framework的major version 都停留在 framework bundle,一个和现有version不兼容的程序依然可以在旧版本下运行。每个 major version 的path 编码了version。例如,path中的字符 “A”表示一个假设的framework的major version:
/System/Library/Frameworks/Boffo.framework/Versions/A/Boffo
当一个程序被构建,linker记录这个程序中可执行文件的path。dynamic linke editor 在运行时使用这个path来查找framework library的兼容版本。因此这个 major version scheme 通过包含所有主要版本,并记录每个可执行文件的主要版本以实现与后向兼容。

何时使用 Major Versions

你应该制作一个新的framework的major version或动态共享库,每当你创建更改时,可能会破环程序的连接。下面的变化可能导致程序破坏连接:
  • 移除公开几口,比如 class,function,method或者结构
  • 重命名一个公开的接口
  • 改标结构的数据layout
  • 添加,修改或者记录类的实例变量
  • 对 C++类添加virtual methods
  • 记录C++类的 virtual methods
  • 改变 C++编译器或者编译器版本
  • 改变一个公开的function或者method的签名
对于function签名的更改包括改变 order,type或者参数数量。从function或者他的参数中添加或者移除 const 标签也可以修改function的签名。
当你改变framework的major version时,你常常让新version变成“current”version。Xcode 自动生成一个符号连接网来指向当前 major version。
在你发现你需要创建一个新major version之前,认真考虑下framework的实现。下面的列表显示了在不需要新的主要版本的情况下合并特性的方法:
  • 填充类和具有保留字段的结构。 无论何时将实例变量添加到公共类中,都必须更改主版本号,因为子类取决于超类的大小。 但是,您可以通过定义未使用的(“保留的”)实例变量和字段来填充类和结构。 然后,如果需要将实例变量添加到类中,则可以定义一个包含所需存储的全新类,并让您的保留实例变量指向它。请记住,填充频繁实例化的类的实例变量或频繁分配的结构的字段会在内存中产生成本。
  • 除非您希望客户使用它们,否则不要public 类,函数或方法名称。您可以自由更改私有接口,因为您可以确定没有程序正在使用它们。声明那些可能在私有头文件中更改的任何接口。
  • 不要删除接口。如果一种方法或功能不再有任何有用的工作要执行,为了兼容性的目的,请将其留下。确保它返回一些合理的价值。即使您为方法或函数添加其他参数,如果可能的话也要保留原来的形式。
  • 请记住,如果添加接口而不是更改或删除接口,则不必更改主版本号,因为旧接口仍然存在。这条规则的例外是实例变量。
许多上述改变不需要为framework创建新的 major version,大部分需只需要改变 minor version 信息。

创建framework 的 Major Version

使用 Xcode创建。
您还可以制作独立动态共享库的主要版本(即,不包含在框架包内的库)。独立库的主要版本以文件名本身编码,如以下示例所示:
libMyLib.B.dylib
为了便于更改主版本,可以使用名称libMyLib.dylib创建符号链接,以指向库的新主版本。使用库的程序可以引用符号链接。当您需要更改主版本时,您可以更新链接以指向新库。
Minor Versions
在framework的major 版本中,你还可以指定 minor version。minor version也称为“兼容版本”,因为他们保留了和已连接的app的兼容性。小版本不修改已存在的公开api。想法,他们添加新的接口或者修改framework的实现,提供新的行为而不改变旧行为。
在任何framework的major version中,一次只有一个minor version存在。后来的minor version简单覆盖前一个。这和major 策略不同,多个major versions在framework bundle里共存。
下面的段落面熟如何指定小版本信息和系统如何使用这些信息。

Minor Version Numbering Scheme

framework使用两个单独的数字来跟踪次要版本信息。「当前版本号」跟踪您的框架的个人版本,主要供您的团队内部使用。您可以使用此数字来跟踪您的framework的一组更改,并且您可以根据需要经常增加它。一个典型的例子就是每次构建和分发框架到内部开发和测试团队时增加这个数字。
框架的「兼容版本号」更重要,因为它标志着您的framework公共接口发生了变化。当你对公共接口进行某些更改时,应该将兼容版本设置为与当前版本的framework相匹配。因此,兼容版本通常滞后于当前版本。只有当你的framework的公共接口发生改变时,这两个数字才会匹配。
请记住,并非所有对framework公共接口的更改都可以通过增加兼容版本来进行匹配。一些更改可能需要您发布一个新的主要版本的framework。

何时使用 Minor Version

以下变更是应该更新version 信息:
  • 添加类
  • 给OC类添加方法
  • 给C++类添加非虚函数
  • 添加公开的结构
  • 添加公开的functions
  • 不更改公共接口的bug fix
  • 不改变公共接口的优化
每次修改了公共接口,必须更新 「兼容版本号」。

运行时的兼容版本号

当一个程序在开发过程中与framework链接时,链接器会在程序的可执行文件中记录开发框架的兼容版本。在运行时,动态链接编辑器会将该版本与安装在用户系统上的框架的兼容版本进行比较。如果程序文件中记录的值大于用户框架中的值,则用户的框架太旧,无法使用。
框架太旧的情况并不常见,但并非不可能。例如,当用户运行比软件所需版本更早的OS X版本时,可能会发生这种情况。发生这种不兼容时,动态链接编辑器会停止启动应用程序并向控制台报告错误。
要在早期版本的框架上运行应用程序,您必须将应用程序与其支持的最早版本的框架链接起来。 Xcode提供了与早期版本的OS X框架链接的支持。

创建 Framework的 Minor Version

使用Xcode修改 current Version和 compatible version。
注意:Xcode中,currentcompatible version numbers应该和target关联,而不是project

版本指南

每当您更改框架中的代码时,还应该修改框架项目中的配置信息以反映更改。 对于简单的更改(如错误修复和大多数新界面),您可能只需增加与框架相关联的次要版本号。 对于更广泛的更改,您必须创建一个新的主要版本的框架。
表1列出了您可以对框架代码进行的更改类型以及您必须对项目文件进行的相应配置更改。 大多数需要主版本或次版本更新的更改都会发生,因为更改会影响公共接口。
Version type Changes Allowed What to do
Major version
删除接口(类,函数,方法等)。 重命名接口。 更改类或结构的布局。 添加,更改或重新排序类的实例变量。 在C ++类中添加或重新排序虚拟方法。 更改函数或方法的签名。 更改C ++编译器或编译器版本。
您必须更改项目的主要版本指示符。 构建您的框架并将新版本合并到您现有的框架目录结构中。
Minor version (public interface changes)
添加一个C ++或Objective-C类。 将方法添加到Objective-C类。 将非虚拟方法添加到C ++类。 添加结构。 添加功能。
增加您当前的版本号并设置您的兼容版本号以匹配。 建立你的框架。
Minor version (no public interface changes)
修复不影响编程接口的错误。 进行不影响编程接口的增强功能。 只将内部使用的接口更改为框架。
增加您当前的版本号。 不要更改兼容版本号。
如果你在需要时,没有更改框架的Major version,那么链接到它的程序可能会以不可预知的方式失败。 相反,如果您在不需要时更改了Major version,则会使用不必要的框架版本混淆系统。
因为Major version可能会对开发造成很大的干扰,所以最好尽可能避免它们。 Avoiding Major Version Changes 描述了可用于在不发布新的主要版本的框架的情况下进行重大更改的技术。
** Framework 绑定
Mach-O库的动态绑定给OS X带来了可观的效果和适应性。通过动态绑定,framework 可以在不需要app 从新连接的情况下更新。在运行时,一个独立 library的代码copy在所有使用的进程之间共享,因此降低了内存使用、提升了系统性能。
动态共享库
framework中的可执行代码是动态连接的,共享库——或者简单的成为一个动态共享库,是一个代码可以共享给多个并发运行程序的库。
动态共享库有你几个好处。一个好处是他们更有效的利用了内存。所有程序共享同样的copy而不是持有一份内存代码的copy。动态共享库也让开发者更简单的处理库代码的bug。因为库是动态连接的,一个新库可以在不重新构建程序(程序依赖这个库)下被安装。

符号连接

动态共享库有和静态连接共享库不同的特征。对于静态连接共享库来说,库内的符号在linke time 执行检查,确保他们存在。如果不存在,触法连接错误。而对于动态共享库,未定义的 undefined 符号在绑定时被延迟直到程序执行。更重要的是,动态链接编辑器只有在程序引用符号时才会解析每个未定义的符号。如果符号没有被引用,不会绑定到程序。
Mach-O动态共享库的内部结构让这种运行时绑定成为可能。组成库的对象代码模块是为了保留它们的单独边界而构建的,也就是说,来自源模块的代码不会合并到单个模块中。在运行时,动态连接editor 自动加载和连接他们需要的模块。幻觉话说,一个模块只有当一个程序引用模块里的符号是才被连接。如果特定module里的符号没有被引用,module不会被连接。
下图实现了这个“lazy linking” 行为。当库function被调用时,模块 a.o 被连接到程序的main 例程。当库方法b在程序方法 doThat中被调用时,模块 b.o  被连接。模块 c.o 永远不会连接因为它没被调用过。

组织你的Framework 代码

作为一个 framework开发者,你应该记住的原则是:设计时考虑各个分离module的按需连接。因为动态链接编辑器总是试图将未解析的符号绑定到同一个模块中,然后再转到其他模块和其他库,你应该确认这些独立代码被放入他们自己的module。比如,自定义allocation和deallocation 例程应该放入相同module。这种技术防止错误符号定义被使用。当一个符号定义在多于一个的共享库出现时,会触发这个问题。然后那些其他符号定义会覆盖正确的那个。
当创建framework时,你必须确认每个符号仅仅被定义一次。另外,“common” 符号不允许出现在库中,你必须使用单独的真实的定义,并且优先于其他C语言的 extern 定义。
当你构建一个程序时,将其与 动态共享库连接,在程序中记录库的安装路径。Apple提供的系统framework的路径时绝对的。第三方framework,路径和包含frameworkapp package相关。这种对库路径的捕获提高了程序的启动性能。动态链接编辑器不是必须搜索文件系统,而是直接进入动态共享库并将其链接到程序中。这意味着,显然,对于一个运行的程序来说,任何必需的库都必须安装在有记录的路径表明它可以被找到的地方,或者它必须安装在框架和库的一个标准fallback位置上。参阅 Installing Your Framework 

库依赖

共享库的用户不需要关系任何库的依赖。当一个动态库被构建,静态连接器存储关于任何可执行的动态库内部的依赖库信息。运行时,动态连接editor 读取这个信息,使用它加载需要的相关库。
所需的版本 是 存储在每个从属库的另一个重要信息。Frameworks和动态库有关联的版本信息。运行时,存储的版本信息会和实际可用的库版本比较。如果可用库太老,动态连接editor 会结束程序来防止未知的行为。

独立的动态共享库

除了创建框架之外,您还可以创建独立的动态共享库。 按照惯例,独立动态共享库具有.dylib扩展名,通常安装在/usr/lib中。 库文件包含库所需的所有代码和资源。
为大多数开发人员创建独立的动态共享库是一种不常见的方法。 在大多数情况下,框架是首选方法。 框架的bundle结构可以包含复杂资源类型,例如nib文件,图像和本地化字符串。
Frameworks 和预绑定
OS X 10.3.4以前,OS X使用一个叫做预绑定prebinding的特性来消除与动态库相关联的可执行程序所产生的加载时间延迟。预绑定开启系统在每个frameworklibrary中的符号地址预计算。预计算的成果是避免 地址空间 libraryframework间冲突。这种冲突在加载时引发极大的性能开销,会明显拖慢程序启动。
在OS X v10.3.4中,对动态装载机的改进使得预绑定在很大程度上变成了不必要的。dynamic loader自己被修改来处理加载时的冲突。使用心得dynamic loader,一个没有预先绑定的应用程序通常至少会比它在预绑定时的系统上的早期版本运行得一样快(有时更快)。
在 OS X v10.4中,引入了另一个更改,以减少在安装新软件后“优化”系统的时间。不是预先绑定所有框架和库,现在只有选择的系统框架是预先绑定的。通过有选择的挑选那些framework需要预绑定,预绑定工具可以紧密打包系统的最常使用的framework到一个比以前小的内存空间。这一步减少了为苹果框架预留的空间,并将其返还给第三方应用程序和框架。
如果您正在开发框架以在10.4之前的OS X版本上运行,则仍应启用预先绑定并指定首选地址。 如果您正在开发OS X v10.4或更高版本的框架,则不需要预先绑定。 在更高版本的系统上预绑定您的框架不会降低性能,但确实需要一些额外的配置步骤,这些步骤将在以下各节中介绍。
注意: 只有在OS X的版本中支持Mach-O可执行文件才可以进行预绑定。

预绑定你的framework

在Xcode中指定framework的预绑定地址。有以下几步:
1,打开Xcode project
2,Groups & Files,选中target,打开编译设置中的预绑定选项
3,添加 Other Liner Flags build setting,添加 -seg1addr flag,带一个你framework的地址,比如:-seg1addr 0xb0000000
4,编译你的framework
当预绑定框架时,使用-seg1addr选项指定首选地址尤为重要。 如果启用预绑定但不指定首选地址,则Xcode使用默认地址0x00000000。 这有一个问题,因为该地址也是所有应用程序的首选地址。 相反,您应该将初始地址设置为保留供应用程序代码和框架使用的内存区域。 有关有效地址范围的列表,请参阅“启动时间性能指南”中的“预先绑定应用程序”。
通过使用otool命令测试binary,你可以确认你framework的推荐地址。参考Finding the Preferred Address of a Framework

找到framework的推荐地址

要查找框架的首选地址,请使用带 -l 选项的 otool 命令来显示框架二进制文件的加载命令。 加载命令包括加载二进制文件每段的虚拟内存地址。 由于大多数段驻留在库的开始位置,所以您需要查看最初的LC_SEGMENT命令以查找库的首选基础地址。
例如,假设你创建了一个库并在您的Xcode项目中为其分配了首选地址0xb0000000。 从终端窗口在库上运行otool -l将显示类似于以下内容的初始加载命令:
注意vmaddr字段的值。 该字段表示二进制文件的首选地址与您在Xcode项目中指定的地址相匹配。

Apple框架和预绑定

在10.4之前的OS X版本中,苹果提供的框架预绑定,并被分配到保留的内存区域。 在OS X v10.4及更高版本中,Apple系统框架在安装操作系统时会动态预配置。 在这两种情况下,苹果保留的内存范围都列在“启动时间性能指南”的“预先绑定应用程序”中。
Framework Weak Linking
开发人员面临的一个挑战是利用OS X新版本中引入的新功能,同时仍支持旧版本的系统。通常,如果应用程序在框架中使用新功能,则没有办法在不支持该功能的早期版本的框架上运行。当尝试使用该功能时,这些应用程序可能无法启动或崩溃。 Apple通过添加对弱链接符号的支持来解决此问题。
当框架中的符号被定义为弱链接时,该符号不必在运行时出现,以便进程继续运行。static linker在任何引用该符号的代码模块中标识弱链接符号。dynamic linker在运行时使用相同的信息来确定进程是否可以继续运行。如果框架中不存在弱链接的符号,只要不引用该符号,代码模块就可以继续运行。但是,如果符号存在,则代码可以正常使用它。
如果你正在更新你自己的框架,你应该考虑让新的符号弱连接。这样做可以让您的框架的客户更容易支持它。您还应该确保您的代码在使用前检查是否存在弱链接符号。
注意:尽管Code Fragment Manager支持自己的弱链接形式,但以下信息仅适用于Mach-O可执行文件。
弱连接和Apple Framework
Apple框架使用可用的宏来确定符号是弱链接还是强链接。苹果在其框架中用可用的宏包装新接口,以指示哪个版本的操作系统首次出现。宏也用于指示不推荐的功能和接口。
根据您的项目支持的OS X版本,/usr/include/AvailabilityMacros.h 中定义的可用的宏为系统接口添加了弱链接信息。当您创建一个新项目时,您可以通过在Xcode中设置部署目标和目标SDK来告诉编译器您的项目支持哪些OS X版本。编译器使用这些设置分别将相应的值分配给MAC_OS_X_VERSION_MIN_REQUIRED和MAC_OS_X_VERSION_MAX_ALLOWED宏。有关如何在Xcode中修改这些设置的信息,请参阅“SDK Compatibility Guide”中的“在Xcode中设置交叉开发”或Xcode帮助。
例如,假设在Xcode中,将OS X v10.2的部署目标(最低要求版本)和目标SDK(允许的最大版本)设置为OS X v10.3。在编译期间,编译器将弱连接OS X 10.3版本中引入的任何接口,同时强链接早期的接口。这将允许您的应用程序继续在OS X 10.2版本上运行,但仍然可以利用更新的功能。
标记符号弱连接
如果您定义了自己的framework,那么您可以使用弱连接属性标记符号为弱链接。如果将新特性引入到现有框架中,那么弱链接尤其合适。为了将符号标记为弱链接,您必须确保您的环境被配置为支持弱链接:
extern int MyFunction() __attribute__((weak_import));
extern int MyVariable __attribute__((weak_import));
使用弱连接符号
如果您的框架依赖于任何Apple或第三方框架中的弱链接符号,则在使用它们之前,您必须检查这些符号的存在。 如果您尝试在没有首先检查的情况下使用不存在的符号,则动态链接器可能会生成运行时绑定错误并终止相应的进程。
如果一个弱链接符号在框架中不可用,链接器将该符号的地址设置为NULL。 您可以使用类似以下代码在您的代码中检查此地址:
弱连接整个框架
当您在另一个框架中引用符号时,大多数这些符号都与您的代码强关联。 为了创建符号的弱链接,包含该符号的框架必须明确地向其添加weak_import属性。 然而,如果你没有维护一个框架并且需要弱链接它的符号,你可以明确地告诉编译器将所有符号标记为弱链接。 要做到这一点,您必须在Xcode设置。
-weak_framework <framework_name>
完,其他请参阅 Framework编程指南(下)

留下评论

Your email address will not be published. Required fields are marked *