performSelector方法
- performSelector在运行时,调用方去找目的方法selector,在编译时不做校验;
延长实行 -- 与RunLoop有关
- 调用performSelector:withObject:afterDelay方法实现延长实行,底层的本质是会创建NSTimer定时器去实行目的方法selector;
- (void)viewDidLoad { [super viewDidLoad]; [self performSelector selector(test) withObject:nil afterDelay:3];}- (void)test { NSLog(@"%s",__func__); NSLog(@"%@",[NSThread currentThread]);}@end
- 在主线程中,延长3秒后实行test方法,可以实行乐成;
- 若将performSelector:withObject:afterDelay方法 放在子线程中调用,如下:
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self performSelector selector(test) withObject:nil afterDelay:3]; });}- (void)test { NSLog(@"%s",__func__); NSLog(@"%@",[NSThread currentThread]);}@end
- 在子线程中调用performSelector:withObject:afterDelay方法 是不会实行test方法的,由于NSTimer定时器依靠于RunLoop才气实行,必须开启子线程的RunLoop,做如下修改:
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self performSelector selector(test) withObject:nil afterDelay:3]; [[NSRunLoop currentRunLoop] run]; });}- (void)test { NSLog(@"%s",__func__); NSLog(@"%@",[NSThread currentThread]);}@end开启子线程实利用命 -- 与多线程有关
- performSelector: onThread:withObject: waitUntilDone: 可指定线程实行目的方法使命;
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"11111"); [self performSelector selector(test) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES]; NSLog(@"22222"); });}- (void)test { NSLog(@"%s",__func__); NSLog(@"%@",[NSThread currentThread]);}@end
- performSelector发送消息与消息的实行是处于同一个线程的;
- waitUntilDone参数为Yes,体现test方法必须实行完成,才会实行之后的打印2222,即会壅闭当火线程的继承实行;
performSelector:方法通报多参数的实现方案
- 第一种方案:将全部参数放到字典大概数组中,再通报聚集即可;
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; NSDictionary *params = @{ @"name" "yanzi", @"age" "30" }; [self performSelector selector(test withObject:params];}- (void)test NSDictionary *)params { NSLog(@"%@--%@",params[@"name"],params[@"age"]);}@end
- 第二种方案:使用objc_msgSend()举行通报,其可以通报多个参数;
#import "ViewController.h"#import <objc/message.h>@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; ((void (*)(id,SEL,NSString *, NSString *, NSString *))objc_msgSend)(self, @selector(testWithParam:param2:param3 ,@"111",@"222",@"333");}//有三个参数的方法- (void)testWithParam NSString *)param1 param2 NSString *)param2 param3 NSString *)param3 { NSLog(@"param1:%@, param2:%@, param3:%@",param1, param2, param3);}@end
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //调用方法 NSArray *paramArray = @[@"112",@[@2,@13],@12]; [self performSelector selector(testFunctionWithParam:param2:param3 withObjects:paramArray];}//可以传多个参数的方法- (id)performSelector SEL)selector withObjects NSArray *)objects{ // 方法署名(方法的形貌) NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector]; if (signature == nil) { //可以抛出非常也可以不操纵。 } //NSInvocation: 使用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值) NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = self; invocation.selector = selector; //设置参数 NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的参数个数 paramsCount = MIN(paramsCount, objects.count); for (NSInteger i = 0; i < paramsCount; i++) { id object = objects; if ([object isKindOfClass:[NSNull class]]) continue; [invocation setArgument:&object atIndex:i + 2]; } //调用方法 [invocation invoke]; //获取返回值 id returnValue = nil; if (signature.methodReturnLength) { // 有返回值范例,才去获得返回值 [invocation getReturnValue:&returnValue]; } return returnValue;}//要调用的方法- (void)testFunctionWithParam NSString *)param1 param2 NSArray *)param2 param3 NSInteger)param3 { NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);}@end |