23

在 Xcode 中,我可以将框架设置为“可选”而不是“必需”,这意味着该框架是弱链接的。

这是否意味着框架仅在某个地方导入时才包含在捆绑包中?

我想弱链接一些使用私有 API的调试框架,并且我不希望它们出现在 App Store 构建中。

4

3 回答 3

20

重要提示:此答案是在 iOS 8 发布之前编写的。虽然技术细节仍然适用于系统框架,但现在可以构建您自己的、动态链接的框架,这些框架包含在您的应用程序包中。有一些限制,例如,只有一个应用程序及其扩展可以链接到嵌入式框架的同一个实例,但事实上,自 iOS 8 以来,自定义、动态链接的框架可能的。如果您想了解更多信息,请参阅本指南使用嵌入式框架共享代码)和 WWDC 2014 会议 416,构建现代框架

原始答案:没有一个(平台)框架真正“包含在捆绑包中”。相反,一旦将框架添加到“Link Binary with Library”构建阶段,您的应用程序就会对框架进行引用(“链接”)。这些框架已预先安装在设备上。当您运行应用程序时,应用程序的所有框架引用都由动态链接器(在设备上)解析,这意味着框架代码已加载,因此您的应用程序可以使用它。

某些框架可能无法在您打算支持的所有设备上使用,例如,在 iOS 6 中引入了 PassKit。如果您在 iOS 5 设备上运行链接到 PassKit 的应用程序,它会在启动后立即崩溃,因为动态链接器不能在设备上找到框架。但是,如果您弱链接 PassKit,如果找不到框架,动态链接器会将框架的所有符号设置为nil。这可以防止应用程序崩溃,您可以在运行时检查符号的可用性,例如:

if ([PKPass class]) {
  // Class is available - use it
  PKPass *pass = [[PKPass alloc] init];
}

[PKPass class]在所有设备/系统上都可以安全使用,因为PKPass类符号将nil在旧系统上使用,并且消息传递nil在 Objective-C 中不是问题。

有关弱链接的更多信息:Apple 文档

要真正回答您的问题:

这是否意味着框架仅在某个地方导入时才包含在捆绑包中?

不会。框架将始终从应用程序链接。只有在您的应用程序运行的实际设备上找不到框架时,才会加载框架。

一种解决方案是为 Debug 和 App Store Builds 设置单独的目标。另一种方法是不使用 Xcode 中内置的“Link Binary with Library”构建阶段,而是通过链接器选项链接 Debug 框架。这些可以分别为每个配置(调试/发布/...)指定,如下所示:

通过链接器标志添加框架

如果您想对其进行弱链接,请改用-weak_framework PassKit(PassKit,当然,这里只是一个示例......插入您的框架的名称)。如果您的 Debug 框架不在默认框架目录之一中,您可能必须提供完整路径或修改框架搜索路径。另外,您可能应该使用宏来确保没有使用调试框架的代码进入 App Store 构建。

编辑:自 Xcode 5 以来的另一个选择是使用@import <FrameworkName>;. 这样,您可以将“链接二进制...”阶段留空并触发代码中框架的链接。然后,您可以使用宏DEBUG来确保某些框架不用于 App Store 构建。有一个很好的答案@import

于 2013-06-05T09:39:26.130 回答
3

我在使用 iAds 时遇到了弱链接。问题是,如果我强链接 iAds 框架并在具有不支持 iAds 的 SDK 的设备上运行该应用程序,那么它只会崩溃。允许弱链接以避免崩溃。我仍然相信,即使使用弱链接,您仍然必须检查框架是否可用。

于 2013-06-04T15:52:31.173 回答
2

这是否意味着框架仅在某个地方导入时才包含在捆绑包中?

这取决于您如何配置方案或目标。

您可以仅使用一种方案进行调试,并仅在其中包含您的可选框架。使用另一个没有可选框架的方案来发布。

方案示例

更新

为此,请将您的新方案基于项目配置并OTHER_LDFLAGS按照hagi 的回答中所述进行设置。

项目配置和方案

于 2013-06-04T16:19:11.317 回答