iOS底层系列32 -- performSelector方法的探索

手机游戏开发者 2024-9-24 14:08:15 11 0 来自 中国
performSelector方法


  • performSelector在运行时,调用方去找目的方法selector,在编译时不做校验;
延长实行 -- 与RunLoop有关


  • 调用performSelector:withObject:afterDelay方法实现延长实行,底层的本质是会创建NSTimer定时器去实行目的方法selector;
- (void)viewDidLoad {    [super viewDidLoad];    [self performSelectorselector(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 performSelectorselector(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 performSelectorselector(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 performSelectorselector(test) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];        NSLog(@"22222");    });}- (void)test {    NSLog(@"%s",__func__);    NSLog(@"%@",[NSThread currentThread]);}@end

  • 控制台的调试效果如下:
1.png

  • performSelector发送消息与消息的实行是处于同一个线程的;
  • waitUntilDone参数为Yes,体现test方法必须实行完成,才会实行之后的打印2222,即会壅闭当火线程的继承实行;
performSelector:方法通报多参数的实现方案


  • 第一种方案:将全部参数放到字典大概数组中,再通报聚集即可;
@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    NSDictionary *params = @{        @"name""yanzi",        @"age""30"    };    [self performSelectorselector(test withObject:params];}- (void)testNSDictionary *)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)testWithParamNSString *)param1 param2NSString *)param2 param3NSString *)param3 {    NSLog(@"param1:%@, param2:%@, param3:%@",param1, param2, param3);}@end

  • 第三种方案:使用NSInvocation举行通报
@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    //调用方法    NSArray *paramArray = @[@"112",@[@2,@13],@12];    [self performSelectorselector(testFunctionWithParam:param2:param3 withObjects:paramArray];}//可以传多个参数的方法- (id)performSelectorSEL)selector withObjectsNSArray *)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)testFunctionWithParamNSString *)param1 param2NSArray *)param2 param3NSInteger)param3 {    NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);}@end
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 20:31, Processed in 0.164243 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表