Search code examples
objective-cxcodecompilationwarningsobjective-c-category

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


I have a category "NSObject+completeOnce". And I use it for main app, watch, widget. But I haven't added it into watch and widget target. Of course I must do it.

My Question is:"Why I don't see any warnings or linking errors in this case? Can I force them?" I have more than 100 classes in my project and sometimes do such mitakes :( It would be good to find some way to check it before runnig.

Category declaration:

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

Usage:

@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

I am sure that I have only one declaration of this method. And I have to emphasize that it is the same problem for all categories. Even for categoryes of my custom classes with 99% unique method name.

enter image description here


Solution

  • What you're seeing is a compound issue. You're right in looking for two types of errors -- compiler warnings/errors, and linker errors. You're not getting either, for two reasons:

    1. There is actually no reason for the compiler to give you a warning. All the compiler needs in order for you to make a method call is the declaration of the method (for it to line up the arguments correctly, prevent common user error, etc.). It doesn't actually need to know that the method will be linked in somehow; that's the linker's job. In this case, since you do declare the methods in a header and include the header, the compiler is satisfied and you will not get a warning, since as far as the compiler is concerned, the method will exist later.
    2. The linker doesn't give an error for the missing methods because Objective-C does not produce linker symbols for methods (see the Objective-C header on that page). Objective-C is inherently a very dynamic language, so it can be impossible to know what a particular method call will do until runtime; in fact, it is possible to define methods at runtime which do not exist statically. The linker only requires class information, which it has; evaluation of methods is left up to the runtime.

    These two things combined lead to the behavior you're seeing. The only way to be sure that these methods don't exist is to simply try to call them at runtime -- where now, you're getting an exception (if uncaught, leads to a crash), since they have not actually been included in the app binary.