多个框架和公共库

Multiple frameworks and common library

正在使用 iOS 8, Xcode 6

假设我有 2 个动态框架,frameworkAframeworkB,它们都依赖于 libC。此外,我有一个同时使用 frameworkAframeworkB 的应用程序。我最初的想法是使 frameworkAframeworkB 伞形框架和 libC 子框架。但是,Apple 建议不要使用 umbrella 框架,这篇 post 描述了为什么 umbrella 框架由于潜在的链接器冲突问题而不是一个好主意。

我的第二个选择是使用 cocoapods(对此仍然很陌生,所以在细节上有点模糊)将 libC 用作 pod,然后将其编译成 frameworkAframeworkB .然而,我突然想到这两个框架仍然有自己的 libC 副本。由于应用程序使用这两个框架,这是否也会导致链接器冲突问题?有没有更好的办法解决这个问题?

更新 @Rob 我从事的项目确实需要复杂的依赖关系管理,但我在问题中保持问题域简单,以试图更好地理解使用 cocoapods 如何以及是否可以帮助解决伞形框架的链接器冲突问题。我与一组编写库的开发人员一起工作,他们可以依赖彼此提供版本化通用 API 的基础库。我们需要将尽可能少的库打包并交付给使用我们的库构建应用程序的不同组织,他们的关键要求之一是我们提供动态框架。

解决大多数问题的最好方法是将所有代码放在一个项目中并进行编译。当你有特殊问题导致问题时,你应该看看其他解决方案,比如静态库,最后是框架。

如果您的代码库包含需要不同构建要求的部分,那么静态库就很有意义。如果所有部分都具有相同的构建设置,那么只需将它们从 "common" 目录 "add files" 放入您的项目并构建您的项目。如果您的构建时间非常长并且某些部分永远不会更改并且您希望能够 "clean" 而无需重建这些部分,则静态库可能很有吸引力。但是等到你开始遇到这个问题,再开始制作复杂的多包项目。

如果你卖闭源库,那么框架就很有吸引力。由于您注意到的原因,您应该强烈避免添加第三方依赖项。如果必须,最好的方法是帮助您的客户将所有部分打包为框架,并在最后让他们 link 一切。但这增加了很多烦恼;所以确保你真的需要那个第三方的作品。

如果您有大量可重用代码,并且其生命周期独立于主要产品,您也可以考虑使用框架。但同样,保持简单。避免里面有第三方的东西,如果你必须有第三方的东西,那么在最后有消费者link它。

(这不是一个新的解决方案,顺便说一句。当你使用 curl 时,如果你想要 SSL,你还需要自己下载并构建 OpenSSL 和 link 它们。Curl 不附带内置 OpenSSL。)

但在绝大多数情况下,这都是大材小用。不要跳到框架。不要跳到图书馆。只需将所有代码放入项目中并编译即可。你90%的问题都会烟消云散。 iOS 特别是项目通常不会那么大。框架解决什么问题?

如果您的组织在许多产品中重复使用大量代码,那么我听说许多团队使用内部 CocoaPods 来管理它会很幸运。但这只是为了简化代码的检查。它仍然全部进入一个项目,您将它们一起编译成一个二进制文件;不需要框架。对于以前非常痛苦的某些类型的问题,动态框架是一个很好的特性。但是,在大多数情况下,它们只是寻找问题的复杂性。

(如果您有这些特殊问题之一,请编辑您的问题,我很乐意进一步讨论您可能如何处理它。)


编辑:(你属于那个 "specialized problem," 所以让我们来谈谈它。我也是,在一个大型多团队 Mac 和 iOS 开发人员中工作了很多年环境。我们几乎尝试了所有不同的解决方案,包括框架。它们在 iOS 上是新的。)

在您描述的组织中,我强烈建议将每个依赖项打包为自己的框架(AFNetworking、JSONKit 等),并将您的每个部分打包为一个框架,然后让应用程序开发人员 link最后他们都在一起了。这样,它与其他动态库(libcurl、openssl 等)相同,需要应用程序开发人员将所有内容 link 放在一起。

在任何情况下,动态框架都不应包含其他可能需要的框架(即框架永远不应打包 "third party" 内容)。那会爆炸的。你不能让它不爆炸。您要么会膨胀、构建冲突或运行时冲突。这就像合并冲突。开发人员必须在某个时刻做出选择。应用程序级别 linking 正在做出选择。

使组件过度依赖其他组件是几十年来麻烦的根源,从 Windows DLL 地狱到 iOS 具有竞争崩溃处理程序的应用程序。所有最好的组件系统看起来都像乐高积木,最终用户可以在其中组装具有最小依赖性的小部件。尽可能让你的内部框架只依赖 Cocoa。这有一些具体的设计影响:

  • 避免直接要求日志记录或分析引擎。提供可适配调用方引擎的委托接口。
  • 避免琐碎的类别(只节省几行代码的方法)。直接写代码就可以了
  • 避免添加不会给您带来很多好处的框架依赖项。不要添加 AFNetworking 只是为了在 NSURLConnection 上节省几行代码。当然,如果您严重依赖另一个框架的功能,那就不同了。但是作为一个框架开发者,你的门槛应该相当高才需要另一个框架。
  • 强烈避免在构建或版本控制中变得聪明。我见过太多这样的案例,人们希望为应用程序级开发人员做所有事情 "automatic",从而使系统变得非常复杂。只说 "you need to link this and import this and put this in your app delegate startup." 不要创建复杂的构建和版本控制系统以在第一次构建或两行初始化逻辑上节省 2 分钟。这些事情会爆炸并浪费时间来解决。不要用 +load 魔法变聪明。只需使其清晰一致即可。

当然,祝你好运。支持其他开发者始终是一个有趣的挑战。