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;
}
由上可知:
- 调用对象方法[self class]和[super class]最终都是返回的是自身的类对象。[super class]调用时是从父类方法列表中开始寻找class方法再进行调用,最终会来到NSObject类里的class方法,所以结果是一致的。
- 类方法的class最终返回的都是自身。
- 获取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;
}
由上可知:
- 调用对象方法isMemberOfClass时,比对的是类对象是否相同。
- 调用类方法isMemberOfClass时,比对的是元类对象是否与参数相同。
- 调用对象方法isKindOfClass时,判断的是自身类对象是否与参数class或者其父类相同。
- 调用类方法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调用,所以出现问题的原因就出来了:
- 在子线程中,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]]);
-
方法
- (void)performSelector: withObject:afterDelay:
中创建的timer添加到了当前的runloop中,但是runloop未开启,所以计时器未开启,所以方法得不到触发调用。 -
要让这个方法得到触发执行,有两种方式:
-》到主线程中调用。
-》在子线程中调用,需要手动去开启线程的runloop,开启的方法在1中。 -
延时任务也可用其它方法来实现,比如
dispatch_after
。