美文网首页iOS底层
OC中一些方法的调用情况

OC中一些方法的调用情况

作者: Sweet丶 | 来源:发表于2020-10-24 16:52 被阅读0次
    一. class方法

    class方法的源码

    + (Class)class {
        return self;
    }
    
    - (Class)class {
        return object_getClass(self);
    }
    
    + (Class)superclass {
        return self->superclass;
    }
    
    - (Class)superclass {
        return [self class]->superclass;
    }
    

    由上可知:

    1. 调用对象方法[self class]和[super class]最终都是返回的是自身的类对象。[super class]调用时是从父类方法列表中开始寻找class方法再进行调用,最终会来到NSObject类里的class方法,所以结果是一致的。
    2. 类方法的class最终返回的都是自身。
    3. 获取superclass时,不管是对象方法还是类方法,返回的都是父类。
    二. isMemberOfClass和isKindOfClass方法

    isMemberOfClass方法的源码

    + (BOOL)isMemberOfClass:(Class)cls {
        return object_getClass((id)self) == cls;
    }
    
    - (BOOL)isMemberOfClass:(Class)cls {
        return [self class] == cls;
    }
    
    + (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    
    - (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    

    由上可知:

    1. 调用对象方法isMemberOfClass时,比对的是类对象是否相同。
    2. 调用类方法isMemberOfClass时,比对的是元类对象是否与参数相同。
    3. 调用对象方法isKindOfClass时,判断的是自身类对象是否与参数class或者其父类相同。
    4. 调用类方法isKindOfClass时,判断的是元类对象是否与参数及其父类相同。
    三. 子线程调用 - (void)performSelector: withObject:afterDelay:;

    在开启的子线程调用延时performSelector方法,实际并未调用的情况如下:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        [self performSelector:@selector(test1:) withObject:@"test1" afterDelay:0.5];
        [self performSelector:@selector(test2:) withObject:@"test2" afterDelay:0.5 inModes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]];
    });
    
    - (void)test1:(NSString *)str{
        NSLog(@"%s", __func__);
    }
    
    - (void)test2:(NSString *)str{
        NSLog(@"%s", __func__);
    }
    

    在开启的子线程中使用方法- (void)performSelector: withObject:afterDelay:, Selector并没有执行,经过查看GUNStep源码

    - (void) performSelector: (SEL)aSelector
              withObject: (id)argument
              afterDelay: (NSTimeInterval)seconds
    {
      NSRunLoop     *loop = [NSRunLoop currentRunLoop];
      GSTimedPerformer  *item;
    
      item = [[GSTimedPerformer alloc] initWithSelector: aSelector
                             target: self
                           argument: argument
                              delay: seconds];
      [[loop _timedPerformers] addObject: item];
      RELEASE(item);
      [loop addTimer: item->timer forMode: NSDefaultRunLoopMode];
    }
    

    由上可知,该方法的本质是创建了一个timer, 然后将timer添加到currentRunLoop中,再由timer触发aSelector调用,所以出现问题的原因就出来了:

    1. 在子线程中,runloop是未开启的,开启runloop需要创建runloop并调用runloop 的开启方法。
    // 创建的方式
    NSRunLoop       *loop = [NSRunLoop currentRunLoop];
    // 开启runloop的方式:首先要添加inputsource或者timer,不然运行了也会立即退出
    
    // 开启永久的runloop,无法被停止。
    - (void)run; 
    //开启直到limitDate的runloop,期间无法被停止。 
    - (void)runUntilDate:(NSDate *)limitDate;
    // 开启一次runloop。
    - (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
    
    // 一般开启一个可控的runloop,方式为:控制shouldKeepRunning变量
    BOOL shouldKeepRunning = YES; // global
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    
    1. 方法- (void)performSelector: withObject:afterDelay:中创建的timer添加到了当前的runloop中,但是runloop未开启,所以计时器未开启,所以方法得不到触发调用。

    2. 要让这个方法得到触发执行,有两种方式:
      -》到主线程中调用。
      -》在子线程中调用,需要手动去开启线程的runloop,开启的方法在1中。

    3. 延时任务也可用其它方法来实现,比如dispatch_after

    相关文章

      网友评论

        本文标题:OC中一些方法的调用情况

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