Skip to content

qianshang/PerformSelector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 

Repository files navigation

PerformSelector

PerformSelector参数扩展

在iOS开发中,我们可以使用使用performSelector来调用方法,但是受限与以下方法,我们想要传递参数的话也就只能传递一个两个或者不传。

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
	// equivalent to the first method with kCFRunLoopCommonModes

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
	// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

所以为了实现多个参数的传递,我们可以使用以下方法:

// 下面的例子都是基于这个方法
- (void)testFirst:(NSString *)argA second:(NSString *)argB third:(NSString *)argC {
    NSLog(@"当前线程:%@", [NSThread currentThread]);
    NSLog(@"first:%@ - second:%@ - third:%@", argA, argB, argC);
}
    1. 将方法的多个参数包装成一个参数(如NSDictionary)

    1. 使用NSInvocation
// 1. 获取方法签名
NSMethodSignature *sign = [self methodSignatureForSelector:aSelector];

// 2. 获取参数个数
NSUInteger number = sign.numberOfArguments;
NSInteger count = MIN(args.count, number - 2);

// 3. 利用NSInvocation对象对方法进行包装
NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sign];

// 3.1 设置方法调用者
[invo setTarget:self];
// 3.2 设置方法名
[invo setSelector:aSelector];
// 3.3 设置方法参数
for (NSInteger i = 0; i < count; i ++) {
    id arg = args[i];
    [invo setArgument:&arg atIndex:i + 2];
}

// 4. 方法调用
[invo invoke];

此处,我是创建了一个NSObjectCategory,暴露一下方法给调用者

- (void)ps_performSelector:(SEL)aSelector onThread:(NSThread *)thr waitUntilDone:(BOOL)wait withObjects:(id)arg, ... NS_REQUIRES_NIL_TERMINATION;

- (id)ps_performSelector:(SEL)aSelector withObjects:(id)arg, ... NS_REQUIRES_NIL_TERMINATION;

具体使用如下:

[self ps_performSelector:@selector(testFirst:second:third:) withObjects:@"AA", @"BB", @"CC", nil];

[self ps_performSelector:@selector(testFirst:second:third:) withObjects:@"E", @"F", nil];
    
[self ps_performSelector:@selector(testFirst:second:third:) onThread:[NSThread mainThread] waitUntilDone:NO withObjects:@"A", @"B", @"C", nil];

// 输出结果如下
/**
当前线程:<NSThread: 0x60000007d500>{number = 1, name = main}
first:AA - second:BB - third:CC
当前线程:<NSThread: 0x60000007d500>{number = 1, name = main}
first:E - second:F - third:(null)
当前线程:<NSThread: 0x60000007d500>{number = 1, name = main}
first:A - second:B - third:C
*/

performSelector在最后也是使用objc_msgSend进行消息转发,这里也可以直接使用objc_msgSend进行转发

// 需要先引入#import <objc/message.h>

SEL sel = @selector(testFirst:second:third:);
    
((void (*) (id, SEL, NSString *, NSString *, NSString *)) objc_msgSend) (self, sel, @"AA", @"BB", @"CC");
    

About

PerformSelector参数扩展

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published