ios NSObject.h 详解

原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456

加载及初始化类

运行时加载类或分类调用该方法,每个类只会调用一次

+(void)load;

类实例化使用前需要先初始化,一个类调用一次,如果子类没有实现该方法则会调用父类方法

+(void)initialize;

loadinitialize区别在于:load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用;load每个类只会调用一次,initialize也只调用一次,但是如果子类没有实现initialize方法则会调用父类的方法,因此作为父类的initialize方法可能会调用多次。

2、分配内存空间及初始化对象

ZMStudent *student = [ZMStudent new];  

ZMStudent *student2 = [[ZMStudent alloc] init];  

ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];  

创建新对象时,首先调用alloc为对象分配内存空间,再调用init初始化对象,如[[NSObject alloc] init];而new方法先给新对象分配空间然后初始化对象,因此[NSObject new]等同于[[NSObject alloc] init];关于allocWithZone方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。

3、给对象发送消息(执行方法)

(1)直接调用

    // 调用无参无返回值方法  
    [student running];  
    // 调用有参无返回值方法  
    [student readingWithText:@"Hello World!"];  
    // 调用有参有返回值方法  
    NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];  

我们通常都采用这种直接调用的方式,给对象发消息执行方法。这种方式调用编译时会自动校验方法、参数、返回值是否正确。因此我们必须在头文件中声明方法的使用。

(2)使用performSelector执行

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

    // 先判断对象是否能调用方法,再执行调用方法  
    if ([student respondsToSelector:@selector(running)]) {  
    // 调用无参无返回值方法  
    [student performSelector:@selector(running)];  
    }  
    if ([student respondsToSelector:@selector(readingWithText:)]) {  
    // 调用有参无返回值方法  
    [student performSelector:@selector(readingWithText:) withObject:@"Hello World"];  
    }  
    if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {  
    // 调用有参有返回值方法  
    NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];  
    }  

使用performSelector:是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用respondsToSelector:检查对象是否能调用方法,否则可能出现运行崩溃。performSelector:常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是performSelector:系统提供最多接受两个参数的方法,而且参数和返回都是id类型,并不支持基础数据类型(如:int, float等)。

(3)使用IMP指针调用

    // 创建SEL  
    SEL runSel = @selector(running);  
    SEL readSel = NSSelectorFromString(@"readingWithText:");  
    SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");  
      
    // 调用无参无返回值方法  
    IMP rumImp = [student methodForSelector:runSel];  
    void (*runFunc)(id, SEL) = (voidvoid *)rumImp;  
    runFunc(student, runSel);  
      
    // 调用有参无返回值方法  
    IMP readImp = [[student class] instanceMethodForSelector:readSel];  
    void (*speakFunc)(id, SEL, NSString *) = (voidvoid *)readImp;  
    speakFunc(student, readSel, @"Hello World");  
      
    // 调用有参有返回值方法  
    IMP sumImp = [student methodForSelector:sumSel];  
    NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (voidvoid *)sumImp;  
    NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));  

SEL 是方法的索引。IMP是函数指针,指向方法的地址。SELIMP是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。
创建SEL对象两种方法:
1、使用@selector()创建
2、使用NSSelectorFromString()创建
获取方法IMP指针两种方法:
1、- (IMP)methodForSelector:(SEL)aSelector; 实例方法
2、+ (IMP)instanceMethodForSelector:(SEL)aSelector; 类方法

4、复制对象

// 两个源数组  
NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"I", nil nil];  
NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"M", nil nil];  
  
// 两个copy  
NSArray *copyArrayI = [sourceArrayI copy];  
NSArray *copyArrayM = [sourceArrayM copy];  
  
// 两个mutableCopy  
NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];  
NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];

copy拷贝为不可变对象,mutableCopy拷贝为可变变量,copymutableCopy都可理解为复制了一个新对象。虽然copy对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。

5、获取Class

    // 获取类  
    Class curClass1 = [student class];  
    Class curClass2 = [ZMStudent class];  
      
    // 获取父类  
    Class supClass1 = [student superclass];  
    Class supClass2 = [ZMStudent superclass];  

6、判断方法

    // 初始化对象  
    ZMPerson *person = [ZMPerson new];  
    ZMStudent *student = [ZMStudent new];  
    ZMStudent *student2 = student;  
      
    // 判断对象是否继承NSObject  
    if ([student isProxy]) {  
    NSLog(@"student对象是继承NSObject类");  
    }  
      
    // 判断两个对象是否相等  
    if ([student isEqual:student2]) {  
    NSLog(@"student对象与student2对象相等");  
    }  
      
    // 判断对象是否是指定类  
    if ([person isKindOfClass:[ZMPerson class]]) {  
    NSLog(@"person对象是ZMPerson类");  
    }  
      
    // 判断对象是否是指定类或子类  
    if ([student isKindOfClass:[ZMPerson class]]) {  
    NSLog(@"student对象是ZMPerson类的子类");  
    }  
      
    // 判断是否是另一个类的子类  
    if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {  
    NSLog(@"ZMStudent类是ZMPerson类的子类");  
    }  
      
    // 判判断对象是否遵从协议  
    if ([student conformsToProtocol:@protocol(NSObject)]) {  
    NSLog(@"student对象遵循NSObject协议");  
    }  
      
    // 判断类是否遵从给定的协议  
    if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {  
    NSLog(@"ZMStudent类遵循NSObject协议");  
    }  
      
    // 判断对象是否能够调用给定的方法  
    if ([student respondsToSelector:@selector(running)]) {  
    NSLog(@"student对象可以调用‘running’方法");  
    }  
      
    // 判断实例是否能够调用给定的方法  
    if ([ZMStudent instancesRespondToSelector:@selector(running)]) {  
    NSLog(@"ZMStudent类可以调用‘running’方法");  
    }  

你可能感兴趣的:(ios NSObject.h 详解)