如果使用了类别但未添加到目标中,则没有警告(任何方法都会自动检查它?

No warnings if category is used but isn't added into target(Any way check it automatically?)

提问人:Nuzhdin Vladimir 提问时间:11/24/2016 最后编辑:Nuzhdin Vladimir 更新时间:11/24/2016 访问量:34

问:

我有一个类别“NSObject+completeOnce”。我用它来做主应用程序、手表、小部件。但我还没有将其添加到监视和小部件目标中。我当然必须这样做。

我的问题是:“为什么在这种情况下我看不到任何警告或链接错误?我能强迫他们吗?我的项目中有 100 多节课,有时会做这样的 mitakes :(最好在跑步前找到一些方法来检查它。

类别声明:

//Category is added only into main target.
@interface NSObject (completeOnce)
+ (void)completeBlockOnce:(void(^)(void))block forKey:(NSString*)key
@end

用法:

@implementation SomeOtherClass
+ (void)method
{
    //It crashes for for widgets.
    //And Here is no any warnings. Also no linking errors at all
    [NSObject completeBlockOnce:^{
       //Some Code
    } forKey:@"FixMigrationBug_1_0_to_1_6"];
}
@end

我确信我只有一个此方法的声明。我必须强调,所有类别都是同一个问题。即使对于具有 99% 唯一方法名称的自定义类的类别。

enter image description here

Xcode 编译 警告 Objective-C-Category

评论

1赞 Itai Ferber 11/24/2016
此类别定义了哪些方法?您确定它们不会与其他现有名称冲突吗?这些方法的调用站点是什么样的?
0赞 Nuzhdin Vladimir 11/24/2016
感谢您的关注,我添加了一些信息。猜猜它包含您问题的答案。
1赞 Itai Ferber 11/24/2016
谢谢你的信息。因此,问题的核心是您在所有平台上导入标头,但是当您不包括为这些目标编译的实际标头时,它们就会崩溃,对吗?如果是这样的话,那么我的猜测是你不会得到编译器错误,因为编译器在头文件中拥有它所需要的一切:方法的声明。编译器并不关心该方法是否存在,它只需要看看它是什么样子的。(由链接器进行验证。链接器可能无法静态地确定这些东西,因为它属于一个类别 -- 这取决于运行时。.m
0赞 Itai Ferber 11/24/2016
至少只是一种预感。我将进一步研究这个问题,看看是否有更深层次的解释。

答:

2赞 Itai Ferber 11/24/2016 #1

你所看到的是一个复合问题。你查找两种类型的错误是正确的 - 编译器警告/错误和链接器错误。你也得不到,原因有二:

  1. 实际上,编译器没有理由给你一个警告。为了进行方法调用,编译器只需要声明方法(以便正确排列参数、防止常见的用户错误等)。它实际上不需要知道该方法将以某种方式链接;这是链接者的工作。在这种情况下,由于您确实在标头中声明了方法并包含标头,因此编译器是满意的,并且您不会收到警告,因为就编译器而言,该方法稍后将存在。
  2. 链接器不会为缺少的方法提供错误,因为 Objective-C 不会为方法生成链接器符号(请参阅该页上的 Objective-C 标头)。Objective-C 本质上是一种非常动态的语言,因此在运行时之前不可能知道特定方法调用将做什么;事实上,可以在运行时定义静态不存在的方法。链接器只需要它所具有的类信息;方法的评估由运行时决定。

这两件事结合在一起,导致了你所看到的行为。确保这些方法不存在的唯一方法是简单地尝试在运行时调用它们 - 现在,你会得到一个异常(如果未捕获,会导致崩溃),因为它们实际上并没有包含在应用程序二进制文件中。

评论

0赞 Nuzhdin Vladimir 11/24/2016
我认为你是对的。但我正在寻找一些方法来避免将来发生此类崩溃。可能是没有解决方案。但我认为我至少必须尝试一下。因为我使用“小部件”和“Apple Watch”。项目中有 1000+ 个文件。而且我无法自己检查它=(。这样的错误在一个月内一次又一次地出现,就像那个拿着勺子的人=(youtube.com/watch?v=9VDvgL58h_Y
0赞 Nuzhdin Vladimir 11/24/2016
可能我的问题标题与我的需求不符=(我会尽量在这方面更准确。
1赞 Itai Ferber 11/26/2016
@ZevsVU 没有编译器支持的解决方案,因为不可能有编译器支持的解决方案,由于上述原因——根本没有办法静态地知道这些方法是否存在。但是,您可以使用工具来解决这个问题:您可以编写一个脚本,该脚本会自动遍历项目中的所有文件,并确保将它们添加到所有目标中。或者,如果您有一个文件列表,这些文件应该位于某些目标上而不是其他目标上,请将它们添加到相应的目标中。