【问题标题】:Framework using library crash使用库崩溃的框架
【发布时间】:2017-12-18 01:34:06
【问题描述】:

我创建了 2 个框架,它们都使用了(两个)我创建的库。

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

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

我做错了什么吗?我应该改用两个单独的库吗?


编辑:

想象一下情况:

框架 A 有这样的方法:startstop。虽然它可以工作,但它委托给方法:infoFromA,frameworkAFinished

框架 B 有这个方法:startstop。虽然它起作用,但它委托给方法:infoFromB,frameworkBFinished

两个启动方法都初始化提到的静态库(我们称之为problematicLibrary)。

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

在应用程序视图viewWillAppear 方法中,我仅使用以下方式启动框架A:

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

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

我检查了初始化是否正常,所有变量在初始化之前都在null的值,并且给库对象一个新的内存地址。

【问题讨论】:

    标签: ios xcode cocoa-touch frameworks


    【解决方案1】:

    对我来说,这听起来像是一个符号冲突。我很惊讶链接器没有捕捉到它,但我认为这是因为您在两个框架中都使用了静态库,而不是简单地使用另一个框架。

    一般来说,我会警告说“这是个坏主意™”。您试图在设计中引入的基本上是依赖管理。就像很多博客文章,特别是 this SO 回答建议一样,您应该避免将框架(以及扩展库)打包到框架中。

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


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

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

    如果您想让这个精美且易于安装到其他应用程序中,我建议您设置一个私有 CocoaPods 存储库并将您的框架变成私有 pod。然后,您可以轻松地将库(或者更确切地说是“新框架 C”)定义为框架 A 和框架 B 的依赖项。然后,当您在应用程序中 pod install 时,cocoapods 会计算出依赖项并将框架 C 自动添加到您的项目中。这个场景正是 cocoapods(或任何依赖管理器)的设计目的。它可以自动化并帮助项目设置,因此最终构建(应用程序)不必动态地确定它可以使用和不能使用的内容。最终结果是一样的。

    试图复制“代码”很快就会变得混乱。框架试图找出使用它们的周围应用程序/项目的东西(比如“我的依赖关系是否已经链接?如果没有,我可以加载我自己的库版本吗?”)可能会导致很多痛。


    好的,作为对您的评论的回应,我将尝试为非 cocoapods 设置提供更详细的操作方法。不过,作为序言,让我说这在我的头脑中有点难以做到,因为我没有现成的示例项目可以玩弄。由于这是“设置一次,然后忘记了很长时间”的一种,我不得不承认我对这些事情的回忆有些模糊,因此将其视为一种“粗略的方向”。您可能需要配置一些不同于我记忆中的东西。因此,特此邀请其他 SO 用户也在这里编辑和更正我的答案。 :)

    • 首先,我不得不说我不确定你是否需要将静态库转换为框架,我认为你不需要我将从这里开始(我从未以这种方式使用过静态库)。 这意味着您可以将构建您的库的项目保持原样。再想一想,您可能必须这样做才能链接到库而不使其成为使用它的框架的一部分。在以下几点中,我仍将这段代码称为“库”,但假设您也能够将其转换为动态框架。

    • 应更改构建框架 A 和框架 B 的项目。我不知道你是如何设置的(作为一个具有各种目标的项目,你是否有一个“开发应用程序”作为其中的一部分来测试框架本身等),但重要的是在构建框架的目标,库应该被链接(即在“Link Binary With Libraries”构建阶段),但复制(即它不能在“Copy Bundle Ressources”构建阶段)。设置您用来运行的任何开发/测试目标可能会很棘手,具体取决于您到目前为止的操作方式。例如,您可能必须在构建设置中手动编辑库搜索路径才能正确编译框架。

    • 最后,您显然需要更改最终应用的项目设置。最初是框架 A 和 B 的一部分的库现在需要直接从其项目链接到,而且很明显,它也需要复制到包中。请注意,将来包含您的任何一个框架(A 或 B 或两者)的任何项目都必须这样做,否则它们将无法工作,因为这些框架期望该库存在(但不再“随身携带” )。

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

    【讨论】:

    • 嗨@Gero,感谢您的宝贵时间。我想我理解你了。所以有两种方式,一种是“丑陋”的,一种是花哨的。对于丑陋的,我不必打包库并将其添加到应用程序中。我读书是为了做类似的事情,但我没能做到。你有什么建议再试一次吗?我从来没有用过CocoaPods,所以我会尝试“丑陋”的方式,然后尝试将其改进为花哨的方式。
    • 我编辑了我的答案,但请记住,在您的案例中,特定的项目设置有很多可能性(从我的角度来看,不知道您的代码和配置)保持一点模糊。
    • 再次感谢您提供有用的答案,并为让您如此痛苦感到抱歉。我已经尝试过你所说的,我已经在“Linked Binaries with Libraries”中链接了库(.a),该库不在“Copy bundle Resources”中。起初我的库与源文件的路径相同,但后来我将它移到桌面并更改了“库搜索路径”以便它可以找到它。我让它编译,但一直保持不变。重复的实现和我可爱的exc_bad_access
    • 对了,谢谢cocoapods的指导和建议,我以后会试试的。
    • Hm... 如前所述,我对静态库的经验有限,但考虑到它们是“静态的”,链接器可能会在生成的框架二进制文件中完全包含符号。然后你必须把你的静态库变成一个动态框架,这个框架被链接起来以使整个考验工作。
    【解决方案2】:
    1. 检查它们是否都针对同一个目标进行编译。
    2. 检查他们是否有权访问相同的目标成员资格。
    3. 检查构建阶段以查看它们是否都存在。

    【讨论】:

    • 当我使用它们将它们导入应用程序时,我可以分别使用它们。也就是说,我可以启动第一个(我们称之为 A)并完成它的所有工作流程,我可以启动第二个(我们称之为 B)并完成工作流程。我可以独立使用 A 或 B,但当时我想做 A 并且当它完成启动 B 或 B 然后 A 时,它崩溃了
    • 我明白,但你真的需要拆分它们吗?
    • 是的,我愿意。我有一个包含各种功能的大框架,我需要做一个包含每个功能的框架。
    【解决方案3】:

    我认为是因为第一个库不能很好地引用第二个。

    另外我认为你不能在另一个框架中导入一个框架。

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

    【讨论】:

    • 首先,感谢您的回答。如果我的库没有很好地引用第二个框架,如果我独立使用第二个框架,我该如何使用它?对于您的第二个问题,我没有在另一个框架中导入框架,这些框架都被导入到应用程序中
    • 在以前的版本中,这两个框架都只是一个使用该库的框架。但现在我需要将它放入两个框架中,并且它们都需要该库。
    • 我了解您的需求,但我无法想象您的问题的原因。您能否从您的代码中发布一些示例,可能有助于我理解原因。
    • 我添加了一个详细的使用示例。如果您需要更多信息,请告诉我。
    猜你喜欢
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多