iOS底层

OC中一些方法的调用情况

2020-10-24  本文已影响0人  Sweet丶
一. 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

上一篇下一篇

猜你喜欢

热点阅读