为什么不鼓励使用“伞形框架”?

52

我想要分发框架A,框架A依赖于框架B。我希望我的框架用户只需要包含框架A,但仍然可以编程访问框架B。

Apple一直使用“Umbrella Frameworks”的概念来实现这一目的,但文档中有这个主题:

不要创建Umbrella Frameworks

虽然使用Xcode可以创建Umbrella Frameworks,但对于大多数开发人员来说,这样做是不必要的,也不推荐这样做。苹果使用Umbrella Frameworks来掩盖操作系统库之间的某些相互依赖性。在几乎所有情况下,您应该能够将代码包含在单个标准框架束中。或者,如果您的代码足够模块化,您可以创建多个框架,但在这种情况下,模块之间的依赖关系将是最小的或不存在的,不应该为它们创建Umbrella Frameworks。

为什么不鼓励使用这种方法?什么使它成为苹果解决互相依赖的框架问题的好方法,但不适用于我的问题?


我也想知道这个。当框架和项目数量增长时,使用git存储库自动设置构建、依赖项目的符号链接、框架/头文件搜索路径等所有有趣的内容可能变得非常繁琐。 - Minthos
9
你在没有证据的情况下假定“伞形框架”是“苹果问题的一个好解决方案”。我认为,相反的情况是正确的:将iOS与旧版OSX进行比较,或将较新版本的OSX与旧版本进行比较,可以看到像CoreGraphics这样的框架正在从“伞形框架”中移出并转为独立的框架。我认为,“伞形框架”的想法是为了缓解Cocoa的发展困境而产生的一种不错的权宜之计,但从未是“苹果问题的一个好解决方案”。也许他们正警告你不要陷入同样的困境。 - Quuxplusone
我投票关闭此问题,因为这个主题太旧了。目前,iOS SDK 8.0及以上版本提供动态框架和Swift语法。因此,这个问题已经不再有用。 - AechoLiu
3个回答

68

如果您是所有相关框架的唯一分发者,并且将所有框架打包成一个单独的版本化包并一起升级,则“伞形框架”才有意义。如果您处于这种情况,那么没问题,但这是一种非常不寻常的情况。在Cocoa开发世界中,除了苹果公司以外,很少有人会处于这种情况。

首先,“伞形框架”只有在您是给定框架的唯一分发者时才有意义。例如,假设您想将libcurl作为伞形框架的一部分包含在内。现在还有其他一些打包程序想将libcurl作为他的伞形框架的一部分包含在内。现在我们有了链接时冲突,这可能会导致链接错误或更糟糕的未定义运行时行为。我自己曾经追踪过这些问题,它们非常令人不愉快。避免这种情况的唯一方法是每个框架/库只有一个版本。伞形框架则鼓励相反的做法。

即使您只是将自己的代码分解为子部分,这意味着其他供应商可能会在其自己的伞形框架中使用您的子框架,从而导致相同的问题。请记住,如果您说作为第三方使用“伞形框架”是可以的,那么其他供应商也可以这样做。

其次,“伞形框架”只有在您控制所有子框架的版本控制时才有意义。在我的经验中,尝试修补互相依赖的框架集合中的一个部分几乎总是会导致灾难。

由于操作系统供应商的系统规模和普及程度,他们面临了一种不同寻常的情况。在某个规模下合理的事情,在另一个规模下可能就不合理了。NSResponder对此完全正确。当您提供一个完整的、数千个软件包的环境作为该平台上编写的每个程序的基础时,权衡是不同的。但即使是苹果也只有少数几个大型的组合框架,并且它们总是围绕着他们提供并控制版本的库的封装器。这主要是为了简化开发人员的工作,否则他们将不得不追踪数十个库和框架以获取编译所需的东西。没有第三方拥有这种情况,因此第三方需要此解决方案的情况非常罕见。要求客户链接两个库与要求他们链接20个库完全不同。如果您提供20个可以共同使用并由您控制的框架,那么也许应该使用一个组合框架,但也许您的框架太多了,这对于第三方来说是不必要的。

我在这里的大部分讨论都是针对OS X的。在iOS上,这对第三方来说不是问题。由于可能发生冲突,静态库绝不能链接其他静态库。

从理论上讲,我在这里讨论的大多数问题都是链接器的基本技术限制。链接器没有很好地管理多个库版本的方法,因此冲突是一个严重的问题。.NET装配件尝试提供更多灵活性。我对.NET开发不太熟悉,无法确定它是否成功。我的经验是,在大型多组件系统中,对于大多数问题,较简单、较不灵活的解决方案最好。(但是,人们总是向往未知的东西...)


如果我只想让我的框架使用第三方框架,那该怎么做呢?我该如何确保我的用户也链接到它呢? - zneak
3
通过指示用户将其包含和链接。对于动态库(OS X 和 iOS 8),你可以自己链接到系统级别的框架。但对于第三方框架,唯一合理的方法是在应用程序级别进行所有链接,由应用程序开发人员控制。为了为调用者自动链接,必须有一个依赖管理系统,但没有内置的依赖管理系统。如果你和你的调用者都选择使用,CocoaPods 提供了一个依赖管理系统。但是必须在应用程序级别处理依赖关系,你无法为你的调用者从框架中处理它。 - Rob Napier
可能的动态链接时冲突有哪些?如果dylibs被递归链接,并且它们具有嵌入路径的安装路径,再加上双层链接,这是否会消除任何链接时冲突的可能性? - Garrigan Stafford

6
一个问题是框架B的版本现在与框架A的版本绑定在一起。这在某些情况下可能是您想要的,而在其他情况下则不是。如果应用程序也想使用框架A并独立使用框架B,则该应用程序可能会发现自己处于B的版本包含在A中但不是所需或所需版本的情况。
框架B是否是一个应用程序可以独立使用的框架?如果是,则可能会遇到此场景。如果B是A之外不可用的框架,则不应遇到此场景。

那是一个非常好的观点,谢谢。在我的情况下,这不是一个问题,但我当然可以看出这是一个因素。 - Ben Dolman

1
在苹果的情况下,他们正在提供大量代码,这些子框架通常是单独修订的。如果您要提供几个吉字节的框架,则可能需要继续制作一个总框架。如果不是,您可能不需要麻烦。

3
这让它看起来似乎只是一个规模的问题。如果它对许多框架都是一个好的解决方案,为什么对于少数框架也不是一个好的解决方案呢?这就像说,只有当你有大量代码时,面向对象设计才是一个好主意。是的,对于那种情况很好,但即使你只有几个类,它也很好用。 - Ben Dolman
1
如果一艘集装箱船是运送数吨货物的好方案,那为什么它对于几袋杂货也不是一个好方案呢? - NSResponder
4
我不想参与比喻战,我的主要问题是:我想将多个框架作为一个框架分发。苹果有很好的解决方案,但他们不鼓励使用。为什么?一个好的答案会告诉我为什么伞形框架只适用于苹果框架,并说明其中存在的问题。你的回答解释了伞形框架对苹果的好处,但你没有解释为什么它们对我不好。 - Ben Dolman
@NSResponder 雨伞框架的使用与您要分发的包的大小无关。我认为这对于苹果来说是可以接受的,因为这些框架纯粹通过他们的分发机制进行分发,所以冲突有一定的可预测性。换句话说,您不太可能无意中在应用程序中包含与苹果框架冲突的内容,但是您的框架用户可能会单独包含其中一个底层依赖项的冲突版本,这并非不切实际。想象一下如果您有100个雨伞框架。 - josephrider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接