首先,我的理解是:
(1)conformsToProtocol:@protocol( )是用来检查对象是否实现了指定协议类的方法;
(2)respondsToSelector:@selector( )用于判断某个类/实例(包括基类)中是否包含某个方法,仅仅判断方法名是否有和@selector(...)中的方法名一致的,而不关注该方法是否有实现,是这样吗???
我主要是对(2)有疑惑,产生疑惑的原因是:
// 首先定义一个分类
// @interface NSArray (MutableDeepCopy)
// - (NSMutableArray *)mutableDeepCopyOfArray;
// @end
@implementation NSArray (MutableDeepCopy)
// - (NSMutableArray *)mutableDeepCopyOfArray {
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[self count]];
for (int i = 0; i < [self count]; i++) {
id oneValue = [self objectAtIndex:i];
id oneCopy = nil;
if ([oneValue respondsToSelector:@selector(mutableDeepCopyOfArray)]) {
oneCopy = [oneValue mutableDeepCopyOfArray];
}
else if ([oneValue respondsToSelector:@selector(mutableCopy)]) {
oneCopy = [oneValue mutableCopy];
}
if (oneCopy == nil) {
oneCopy = [oneValue copy];
}
[newArray addObject:oneCopy];
}
return newArray;
}
@end
// - (void)touchesBegan:(NSSet<UITouch > )touches withEvent:(UIEvent *)event
{
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:12];
NSNumber *Num = [NSNumber numberWithInteger:12345];
[arr addObject:Num];
NSMutableArray *arr2 = [arr mutableDeepCopyOfArray];
}
// 当数组中包含了NSNumber这种类型时,使用该分类方法执行深拷贝时,会报错;
错误很常见,很好理解,如下:
-[__NSCFNumber mutableCopyWithZone:]: unrecognized selector sent to instance 0xb000000000004d23
当我把 else if ([oneValue respondsToSelector:@selector(mutableCopy)]) 换成
else if ([oneValue conformsToProtocol:@protocol(NSMutableCopying)])时,程序正常执行,不报错;
所以,我觉得, respondsToSelector:@selector(mutableCopy),仅仅是从调用对象(或其父类)中,寻找是否有方法名为mutableCopy的方法,只要找到该方法就返回YES,并不强调一定要有mutableCopy方法的实现;而且恰好NSObject中有mutableCopy方法的声明,所以恰好能返回YES,但程序在执行后,崩溃了,因为mutableCopy方法没有实现,即mutableCopyWithZone:方法没有实现;
conformsToProtocol is to detect whether a class complies with a certain protocol. It has nothing to do with whether the class implements the method of the protocol (of course, the method declared required in the protocol must be implemented).
respondsToSelector is to detect whether a class or its parent class can respond to a certain message. In your example, NSObject can respond to mutableCopy messages, and NSNumber is a subclass of NSObject, so there is no problem with respondsToSelector returning true. respondsToSelector does not just check the method name, it does not matter if there is a method declaration but no implementation. It is a requirement that must be implemented. There is an implementation of the mutableCopy method in the NSObject class, as stated in the documentation:
Returns the object returned by mutableCopyWithZone:.
This is a convenience method for classes that adopt the NSMutableCopying protocol. An exception is raised if there is no implementation for mutableCopyWithZone:.
So we can guess that the mutableCopy method of NSObject is to call mutableCopyWithZone and return the result. If the class does not implement the mutableCopyWithZone method, an exception will be thrown.
Your program above crashed, not because the mutableCopy method was not implemented, nor because the result returned by respondsToSelector was "inaccurate", it was actually expected.