使用库崩溃的框架

时间:2017-07-13 10:16:30

标签: ios xcode cocoa-touch frameworks

我有两个由我创建的框架,它们使用(两个)我也创建的库。

第一个框架初始化库并完成其所有工作流程。完成第一个框架后,第二个框架必须启动。 但是当第二个开始时,在初始化库之后,使用两个框架的应用程序崩溃并出现exc_bad_access错误。

显然,库是正确创建的,但是如果我在第二个框架中注释代码行来初始化库,则工作流继续(之后崩溃,因为它没有库初始化)。

我有什么问题吗?我应该使用两个独立的库吗?

修改

想象一下情况:

框架A有以下方法:startstop。虽然它有效但却委托给方法:infoFromAframeworkAFinished

框架B具有以下方法:startstop。虽然它有效但却委托给方法:infoFromBframeworkBFinished

两个start方法都初始化了所提到的静态库(让我们称之为problematicLibrary)。

两个框架都提供了一些视图来实现其功能。因此,让我们举一个应用程序工作流程的例子。

在应用视图viewWillAppear方法中,我只使用以下命令启动框架A:

[FrameworkA start];,这将初始化库并呈现视图。使用此视图(使用我的problematicLibrary),一些信息将委派给infoFromA委派方法。在委托完所有信息后,它将委托给frameworkAFinished

当FrameworkA委托给frameworkAFinished时,我启动下一个框架:[FrameworkB start]。作为另一个框架,它将初始化库并呈现视图。在调试时,完成了库的所有初始化(创建所需对象的实例并创建了库的新实例),并且在呈现视图时,它通过viewDidLoad方法然后抛出在exc_bad_access初始化行(已经完成并继续呈现视图!!)的problematicLibrary错误,而不从视图中进入任何其他方法。

我已经检查了初始化是否运行良好,并且所有变量在初始化之前都处于null值,并且为库对象提供了新的内存地址。

3 个答案:

答案 0 :(得分:5)

这听起来像是一个符号冲突给我。我很惊讶链接器没有抓住它,但我认为这是因为你在你的框架中使用静态库而不是简单的另一个框架。

一般来说,我警告说"这是一个坏主意™"。您尝试在设计中引入的内容基本上是依赖关系管理。像很多博客文章一样,特别是this SO答案建议,你应该避免将框架(和扩展库)打包到框架中。

在你的场景中发生的最有可能是这样的(我承认我在这里猜测一下):你将库链接到Framework A.因此,库成为了一个固定的部分它。它的符号在其中,即使您没有在任何头文件等中将它们暴露给应用程序。只要你只使用它,一切都很顺利。然后是框架B,其中库也是固定部分。即使你无法从你的应用程序中看到它,它内部也会有相同的符号。然而,这与已经由框架A加载的符号发生冲突,因此崩溃(如上所述,这通常会被链接器捕获,但我想你会被欺骗"它通过预先构建框架来实现并将库打包在其中)。也许其他人可以更详细地解释这一点,但这很快就会成为你如何寻求解决方案的重点。从我如何看待它,它只是以这种方式工作。

所以这里有一个关于如何解决问题的建议:

如果你真的,真的需要像这样分割 (你的应用程序中使用的两个框架使用相同的依赖关系),我建议从框架中删除库(即让它们依赖在它上面,但不包装实际的.a文件)并正确记录。然后将库添加到 app项目,就像添加框架一样。

如果您希望将这种想象力轻松安装到其他应用中,我建议您设置私有CocoaPods存储库并将您的框架转换为私有容器。然后,您可以轻松地将库(或者更新的框架C")定义为框架A和框架B的依赖项。当您在应用程序中pod install时,cocoapods会计算出依赖关系并添加框架C自动进入您的项目。这种情况正是cocoapods(或任何依赖管理器)的设计目标。它自动化并有助于项目设置,因此最终构建(应用程序)不必动态地弄清楚它能够和不能使用的内容。最终结果是一样的。

尝试在代码中复制#34;"很快变得凌乱。框架试图找出使用它们的周围应用程序/项目的事情(比如"我的依赖关系某某已经链接过了?如果没有,我可以加载我自己的库版本吗?")会导致很多痛苦。

好的,在回复您的评论时,我会尝试更详细地介绍非cocoapods设置。不过,作为序言,请允许我说,有点难以做到,因为我没有准备好的样本项目。因为这是其中之一"设置一次,然后忘记它很长一段时间"我不得不承认我对这些东西的回忆有点模糊,所以把它看作是一种粗略的方向"。您可能需要配置的内容与我回忆它们的方式不同。因此,特此邀请其他SO用户在此编辑和更正我的答案。 :)

  • 首先,我不得不说我不确定你是否需要将你的静态库转换成一个框架,或者不是为了这个,我认为你没有'所以我将从这里开始(我从未使用过静态库)。 这意味着您可以保留按原样构建库的项目。第二个想法,您可能必须这样做以便能够链接到库而不使其成为使用它的框架的一部分。我仍然会将此代码称为" library"在以下几点中,我们假设您也可以将其转换为动态框架。

  • 应该更改构建框架A和框架B的项目。我不知道你是如何设置的(作为一个有各种目标的项目,你是否有一个开发应用程序"作为测试框架的一部分,等等),但是重要的是,在构建框架的目标中,库应该链接(即在"链接二进制文件库和#34;构建阶段),但复制(即它不得在"复制捆绑资源"构建阶段)。设置用于运行的任何开发/测试目标可能很棘手,具体取决于您到目前为止的操作方式。例如,您可能必须在构建设置中手动编辑库搜索路径才能正确编译框架。

  • 最后,您需要更改最终应用的项目设置。最初属于框架A和B的库现在需要直接从其项目链接,显然,它也需要复制到包中。请注意,将来包含任一框架(A或B或两者)的任何项目都必须这样做,否则它们将无法工作,因为这些框架期望库存在(但不再是#34;带上它们")。

尽管有这么长的文本墙,但我认为它不应该 复杂,但是你可能仍然想看看cocoapods can support you是怎么样的这个,也许它对未来很有帮助。链接的文章期望有关如何使用pod并编写一个的基本知识,但网站上的其他指南很好地解释了这一点。我只是这样说,因为最后,当在项目中使用cocoapods添加多个引入依赖关系的库/框架时,它基本上按照我上面描述的方式设置你的项目。它使用了一些花哨的shell脚本,确保将所有内容复制到正确的文件夹等,但总的来说它是如何工作的:pod的podspec告诉cocoapods你的应用程序中包含哪些附加pod工作(pod希望在那里依赖,但不会自己带来#34;

答案 1 :(得分:3)

  1. 检查他们是否同时针对同一目标进行编译。
  2. 检查他们是否可以访问相同的目标会员资格。
  3. 检查构建阶段以确定它们都在那里。

答案 2 :(得分:0)

我认为因为第一个图书馆并不是很好。引用第二个。

此外,我认为您无法在另一个框架内导入框架。

为了简化操作,您可以将两个框架合并到一个框架上。 您还可以添加一个回调(使用协议或闭包)来通知第一个工作流的结束,并使用此回调来初始化第二个框架。这样就不会自动进行初始化。