抛个砖
iOS里类的方法都有方法签名吗?
答案是否。举个栗子
NSString *str = [[NSString alloc] initWithBytes:"" length:2 encoding:(NSUTF8StringEncoding)];
SEL selector1 = @selector(initWithBytes:length:encoding:);
NSLog(@"%@", [NSString instanceMethodSignatureForSelector:selector1]);
NSLog(@"%@", [[NSString new] methodSignatureForSelector:selector1]);
上述打印结果两个都是null。为什么呢?
因为上述对象的实现是类簇啊
解析
为什么是null呢?
我们打断点po [[NSString alloc] class]
得到的结果是 NSPlaceholderString
。
而调用initWithBytes:length:encoding:
之后得到的类型是NSTaggedPointerString
为什么 alloc 和 init 之后得到的类型不一样呢?
因为这里使用 类簇 的方式实现的。
什么是类簇
类簇其实是一种设计模式,为了解决不同类型对象之间有很多相同点问题,为了让使用者无需关心实现细节,可以更方便的使用对象,而使用的一种设计模式。
这里是官方解释,可以更好的理解类簇:
https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html
例子
例如我们常用的NSNumber,在我们使用的数据类型里,不管是char,bool,int,double还是float等,最后对应的对象都是NSNumber类
NSLog(@"%@", [[NSNumber alloc] class]);
NSLog(@"%@", [[[NSNumber alloc] initWithInt:6] class]);
NSLog(@"%@", [[[NSNumber alloc] initWithBool:YES] class]);
例如以上输出结果为:
test[20520:1899589] NSPlaceholderNumber
test[20520:1899589] __NSCFNumber
test[20520:1899589] __NSCFBoolean
其过程和工厂模式类似,alloc的时候分配一个工厂,init的时候产生真正的实例对象
以上的类型的继承关系如下:
NSPlaceholderNumber–》NSPlaceholderValue –》NSNumber
__NSCFNumber –〉 NSNumber
__NSCFBoolean –〉 NSNumber
可见苹果把具体的业务实现的类没有对外暴漏,那么我们实际使用的时候只需要使用NSNumber即可,所有的具体业务实现类都实现了NSNumber的抽象接口,所以我们不需关心具体的实现细节
如果自定义一个类簇的具体实现类
我们可以看苹果官方的例子:
#import <foundation/foundation.h>
@interface MonthArray : NSArray
{
}
+ monthArray;
- (unsigned)count;
- (id)objectAtIndex:(unsigned)index;
@end
#import "MonthArray.h"
@implementation MonthArray
static MonthArray *sharedMonthArray = nil;
static NSString *months[] = { @"January", @"February", @"March",
@"April", @"May", @"June", @"July", @"August", @"September",
@"October", @"November", @"December" };
+ monthArray
{
if (!sharedMonthArray) {
sharedMonthArray = [[MonthArray alloc] init];
}
return sharedMonthArray;
}
- (unsigned)count
{
return 12;
}
- objectAtIndex:(unsigned)index
{
if (index >= [self count])
[NSException raise:NSRangeException format:@"***%s: index
(%d) beyond bounds (%d)", sel_getName(_cmd), index,
[self count] - 1];
else
return months[index];
}
@end
一定要注意实现的具体业务类要继承并实现抽象类的所有方法
这里只实现了objectAtIndex是因为其他的lastobject 等都是调用这个方法来实现的,所以只实现这个方法即可