【问题标题】:Calling method on category included from iPhone static library causes NSInvalidArgumentException调用 iPhone 静态库中包含的类别的方法会导致 NSInvalidArgumentException
【发布时间】:2010-10-30 06:59:33
【问题描述】:

我创建了一个静态库来存放我的一些代码,例如类别。

我在“UIView-Extensions.h”中有一个 UIView 类别,名为 Extensions。

在这个类别中,我有一个方法叫做:

- (void)fadeOutWithDelay:(CGFloat)delay duration:(CGFloat)duration;

在调试配置的模拟器上调用此方法可以正常工作。

但是,如果尝试在设备上运行应用程序,我会收到 NSInvalidArgumentException:

[UIView fadeOutWithDelay:duration:]: unrecognized selector sent to instance 0x1912b0
 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIView fadeOutWithDelay:duration:]: unrecognized selector sent to instance 0x1912b0

似乎出于某种原因 UIView-Extensions.h 未包含在设备构建中。


我检查过/尝试过的内容

我确实尝试为 NSString 包含另一个类别,但遇到了同样的问题。

其他文件,如整个类和函数都可以正常工作。这是类别发生的问题。

我清理了所有目标,但没有解决问题。

我检查了静态库项目,类别包含在目标的“复制标题”和“编译源”组中。

静态库包含在主要项目“将二进制文件与库链接”组中。

另一个我添加了静态库的项目可以正常工作。

我删除并重新添加了静态库,但没有运气

-ObjC 链接器标志已设置

有什么想法吗?


纳米输出

libFJSCodeDebug.a(UIView-Extensions.o):
000004d4 t -[UIView(Extensions) changeColor:withDelay:duration:]
00000000 t -[UIView(Extensions) fadeInWithDelay:duration:]
000000dc t -[UIView(Extensions) fadeOutWithDelay:duration:]
00000abc t -[UIView(Extensions) firstResponder]
000006b0 t -[UIView(Extensions) hasSubviewOfClass:]
00000870 t -[UIView(Extensions) hasSubviewOfClass:thatContainsPoint:]
000005cc t -[UIView(Extensions) rotate:]
000002d8 t -[UIView(Extensions) shrinkToSize:withDelay:duration:]
000001b8 t -[UIView(Extensions) translateToFrame:delay:duration:]
         U _CGAffineTransformRotate
000004a8 t _CGPointMake
         U _CGRectContainsPoint
         U _NSLog
         U _OBJC_CLASS_$_UIColor
         U _OBJC_CLASS_$_UIView
         U ___CFConstantStringClassReference
         U ___addsf3vfp
         U ___divdf3vfp
         U ___divsf3vfp
         U ___extendsfdf2vfp
         U ___muldf3vfp
         U ___truncdfsf2vfp
         U _objc_enumerationMutation
         U _objc_msgSend
         U _objc_msgSend_stret
         U dyld_stub_binding_helper

【问题讨论】:

  • 异常消息具体说了什么?
  • 我发现你的这部分问题很有趣the categories are included in the target's "copy headers" and "compile sources" groups... 通常这些类别由包含所述静态库的项目调用.. 为什么它应该包含在copy headers 部分?苹果在其最近发布的tutorial 中没有提及它
  • 正是那个步骤解决了我的问题

标签: iphone cocoa-touch xcode exception


【解决方案1】:

唯一有效的解决方案是包括:

“-all_load”

在其他链接器标志中。

编辑:请务必将此标志添加到包括静态库在内的项目中,而不是添加到静态库本身。

我知道这不是正确的方法,但它现在有效。

这可能是 OS 3.0 的问题,因为这也是 Three20 的解决方法。

【讨论】:

  • 查看另一个问题的答案:stackoverflow.com/questions/2906147/…
  • 只是想补充一点,您需要将此标志添加到包括静态库在内的项目中,而不是在静态库本身中。
  • 只是想谢谢你!这帮助很大。
【解决方案2】:

不幸的是,由于哪些类别可以工作以及 Objective-C 运行时的动态特性,并不是所有的东西都适用于静态库。您收到此错误的原因是静态库中的类别实现从未真正链接到可执行映像,因为编译器无法知道在运行时将需要实现代码。

为了解决这个问题,您可以强制链接器从静态存档中复制任何和所有 Objective-C 类和类别图像的目标文件。缺点是您的可执行文件将包含您可能根本不使用的类的图像代码。要让链接器包含类别代码,请将 -ObjC 添加到 Xcode 中的 OTHER_LD_FLAGS 构建设置中。您的类别实现现在将从静态存档复制到您的可执行文件,并且您不会遇到运行时异常。

【讨论】:

  • 嗯,这就是问题所在。您是否尝试在存档上运行 nm 以确保目标代码确实进入存档?
  • Corey - 您是否确保在 所有 配置中设置了 -ObjC 链接器标志,而不仅仅是在调试配置中?
  • ...您是否使用 nm 检查代码是否存在。我认为这是可能的解释。
  • 感谢您的建议。我确实检查了“所有配置”。但是,我没有使用 nm 来检查存档(我必须查找它)。我跑了 nm 并在我的问题中发布了(我认为是)相关部分。您(Jason 和 Roger)的建议让我想到了在 sdk 3.0 beta 中包含 Three20 的一个已知问题。要解决此问题,请添加另一个链接器标志:“-all_load”。这实际上解决了问题,应用程序成功运行。但我不禁认为这个解决方案有问题(包括我不需要的代码)。了解所有这些信息后,解决此问题的“正确”方法是什么?
  • 我最后的评论可能是可疑的。需要明确的是:我的应用程序现在正在运行,但仅设置了“-all_load”标志。
【解决方案3】:

我刚刚与一位 Apple 工程师讨论过这个问题,这个问题已经在 ld 版本 >100 中得到解决。这包含在 Xcode 4 中。他引导我完成了这个,我自己尝试了一下,确实修复了类别问题。

取出“-all_load”并使用新链接器返回构建设置中的“-ObjC”。

【讨论】:

  • 不幸的是,这在 Xcode4 中仍然不起作用。您可以通过在类别文件中创建一个空类来解决它,该类适用于除单元测试之外的所有内容。除非您将文件与测试目标相关联,否则即使 -all_load 也无法使单元测试找到您的类别代码。
  • 确实,它在 Xcode 4 中被重新破解。我已经了解了 -force_load 标志,它可以解决问题。
【解决方案4】:

如果您使用的是 Xcode 3.2,则可以避免使用 -all_load,而仅对有问题的库使用 -force_load,这应该会更有效。

最近更新的 Apple 技术 QA 对此进行了描述:http://developer.apple.com/mac/library/qa/qa2006/qa1490.html

【讨论】:

    【解决方案5】:

    需要-all_load-force_load 链接器标志来链接类别的问题是fixed in LLVM。该修复程序作为 LLVM 2.9 的一部分提供 包含该修复程序的第一个 Xcode 版本是 Xcode 4.2 与 LLVM 3.0 一起提供。 使用 Xcode 4.2 时不再需要上述修复。链接 ObjC 二进制文件时仍需要 -ObjC 标志

    【讨论】:

    • 我正在使用 LLVM 3.0 和 XCode 4.2.1,但我仍然遇到静态库中的类别不起作用的问题。
    • 但是您使用的是-ObjC 链接器标志?这是并且将仍然是必需的。不再需要 -all_load 标志。
    • 是的,使用 -ObjC 标志编译是可行的。创建一个简单的测试类别后,编译工作。旧项目文件中一定有什么奇怪的东西,在将所有代码添加到一个全新的项目后,一切正常。
    【解决方案6】:

    我最近遇到了这个问题。当我注意到另一个类别我有 DID 工作时,我无法让 -all_load 工作。我对这个类别很懒惰,并将其包含在另一个文件中。

    我最终创建了一个虚拟类(没有方法、实例变量)并将我的类别的实现包含在该虚拟类的 .m 文件中。这样做之后,即使我删除了 -all_load 标志,我的类别也开始工作。

    这是在 iPhone OS 3.1.3 上。

    这当然不是修复它的正确方法,但它似乎有效。

    完整的示例代码在我的blog 上,用于我的(琐碎)类别。

    【讨论】:

      【解决方案7】:

      我刚刚遇到了同样的问题,但是添加了所描述的标志(-ObjC、-all_load、-force_load)的任何组合都不起作用。

      原来我在将文件添加到项目时没有选中“添加到目标”框。我从项目中删除了文件并再次添加它们,这次确保选中了该框。这解决了问题。

      【讨论】:

        【解决方案8】:

        在过去,我能够强制使用 -u .objc_category_name_UIView_Extensions 关联类别,但 3.0 开发环境已损坏,唯一的选项似乎是 -all_load。

        【讨论】:

          【解决方案9】:

          我的静态库中的类别也有同样的问题。就我而言,“-all_load”没有帮助,因为它会导致大量构建错误(我的静态库是另一个私有 C/C++ 库的包装器)。

          我通过http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html 建议的 hack 解决了这个问题,它只涉及向类别文件添加一个虚拟(空)类定义。使用这个 hack,我保留了“-ObjC”,但在应用程序链接器设置中删除了“-all_load”,它在设备上运行良好。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-10-16
            • 2011-12-04
            • 1970-01-01
            • 1970-01-01
            • 2012-05-13
            • 2011-10-08
            • 2012-09-04
            相关资源
            最近更新 更多