美文网首页
ios NSObject.h 详解

ios NSObject.h 详解

作者: 致在路上的我们 | 来源:发表于2018-03-01 15:35 被阅读0次

    原文地址: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 详解

          本文链接:https://www.haomeiwen.com/subject/mkabxftx.html