- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay
是NSObject分类中的方法:
// 位于NSRunLoop.h头文件中
@interface NSObject (NSDelayedPerforming)
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
@end
某次用类如ViewController直接调用- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay
方法,运行成功:
[ViewController performSelector:@selector(test:) withObject:@"abc" afterDelay:0.5];
运行成功原因:NSObject的方法都可以使用类方法直接调用
我们先看下面代码,首先实现NSObject和NSString的两个分类:
#import <Foundation/Foundation.h>
@interface NSObject (myTest)
- (void)testFunc;
@end
@interface NSString (myTest)
- (void)testFunc;
- (void)testString;
@end
@implementation NSObject (myTest)
-(void) testFunc
{
NSLog(@"NSObject testFunc: 执行");
}
@end
@implementation NSString (myTest)
- (void)testFunc
{
NSLog(@"NSString testFunc: 执行");
}
- (void)testString {
NSLog(@"NSString testString: 执行");
}
@end
在ViewController中分别使用类调用分类中的方法:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[NSObject testFunc];
[NSString testFunc];
[NSString testString];
}
@end
问题:
1.首先是否能成功编译
2.如果能成功编译执行结果是什么,为什么会出现这个结果呢
回答:
1.不能成功编译, [NSString testString]会报如下错误
No known class method for selector 'testString'
从错误原因可以明显看到 NSString没有testString类方法。
对编译不成功的代码删除后如下重新编译,成功运行
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[NSObject testFunc];
[NSString testFunc];
}
@end
2.运行结果:
2018-05-03 15:58:22.668416+0800 test--OC-ObjectModel[12480:498039] NSObject testFunc: 执行
2018-05-03 15:58:22.668791+0800 test--OC-ObjectModel[12480:498039] NSObject testFunc: 执行
NSString和NSObject调用testFunc方法执行结果一样,最后都是执行NSObject分类的testFunc方法。
3.分析原因:
NSObject实例方法是特殊的,可以使用类来调用,这个特殊性也是由于OC对象模型决定的,类对象模型里主要包括实例对象-》类对象-》类元对象, 1)实例方法调用会从类对象开始搜索方法,如果在类对象里没有搜索到方法,则沿父类对象网上搜索,直到NSObject这个类对象为止, 2)类方法调用会从元类对象开始搜索方法,如果在元类对象里没有搜索到方法,则沿父元类对象网上搜索,到NSObject这个元类对象还是没有搜索到,则会搜索NSObject这个元类对象的父对象NSObject类对象。
所以,上面两个类方法调用都沿着元类对象一直找到的NSObject这个类对象。
尝试:依据方法搜索原理,如果使用实例调用类方法会报错的,大伙可以自己试验下。
参考文章:iOS 方法调用的过程