OC 类簇

Posted by Maqy on February 10, 2018

抛个砖

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 等都是调用这个方法来实现的,所以只实现这个方法即可