Categories
Development

Xcode wackiness

Let’s just say I have a protocol that conforms to NSObject and NSCoping. It was something like this.

@protocol MyProtocol <NSObject, NSCopying>

- (void)example_doSomethingWithMyProtocol:(id<MyProtocol>)protocol;

@end

And also have a class, that has a method, and conforms to the protocol with a category.

@interface MyClass : NSObject <NSCopying>

@property (nonnull, nonatomic, copy) NSString *myString;

- (instancetype)initWithString:(NSString *)string;

- (NSString *)doSomethingWithMyClass:(MyClass *)myClass;

@end

@interface MyClass (Example) <MyProtocol>

@end

And the implementation looks something like this

@implementation MyClass

- (instancetype)initWithString:(NSString *)string
{
    self = [super init];
    if (self) {
        _myString = string;
    }
    return self;
}

-(NSString *)doSomethingWithMyClass:(MyClass *)myClass
{
    return [NSString stringWithFormat:@"%@ + %@", self.myString, myClass.myString];
}

- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return self;
}

@end

@implementation MyClass (Example)

- (NSString *)example_doSomethingWithMyProtocol:(id<MyProtocol>)protocol
{
    if (![protocol isKindOfClass:[MyClass class]]){
        return nil;
    }

    return [self doSomethingWithMyClass:protocol];
}

@end

So at this point, Xcode is happy. No warnings and no errors.

Let’s start the wackiness.

Let look at our protocol again. I don’t think we need to require NSCopying anymore, so let’s remove it. So our protocol now looks like this.

@protocol MyProtocol <NSObject>

- (void)example_doSomethingWithMyProtocol:(id<MyProtocol>)protocol;

@end

Let’s build and compile.

Whats this 1 warning! Heres the warning.

Why didn’t this warning show up before removing NSCopying. ¯\_(ツ)_/¯ You could just cast it, sure but where is the fun in that. Ok lets rest our protocol to the original. Yay, the warning wen’t way. Let’s now remove NSCopying from our class.

@interface MyClass : NSObject
...
@end

Oh, no we have a new warning.

This one has a “fix it” so let’s apply it. It add a copy with zone, so let’s just return self. If you noticed from before we already have a copy with zone method. We’re going to compile now, ok no errors but we have a new linker warning.

instance method 'copyWithZone:' in category from /.../MyClass.o overrides method from class in /.../MyClass.o

Oh dear, that doesn’t look good. Why didn’t it find the original when implementation. ¯\_(ツ)_/¯

What was the point of this exercise, well nothing and what’s some conclusions we can make. Well we can conclude that Xcode is wacky and does wacky things but if you work with Xcode, you already knew that. If you want the code from this experiment to experience the wackiness for yourself, you can get it here.