目的
参考NSProxy
的实现,那么我们需要通过对多个消息的转发如何做呢?
- 如何存储对象,强引用集合对象已经不可取,会使得对象引用计数+1,所以可以采用
OC
中弱引用集合NSPointerArray
参考以下文章:
http://www.isaced.com/post-235.html
https://www.jianshu.com/p/9d1c34999f3e
- 通过消息转发机制中的
forwardingTargetForSelector
方法,我们使用performSelector
方法有一个问题是,当方法返回值不确定时,对其返回值的引用关系如何处理。返回值需要保存吗?
对于第二个问题,由于各个类中的方法返回值
可能不一,通过方法签名的返回类型来判断处理或许是一个好的选择,但是感觉并没有必要。
类似下面这种返回值类型判断:
NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
if(methodSig == nil) {
return nil;
}
const char* retType = [methodSig methodReturnType];
if (strcmp(retType, @encode(void)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
return nil;
}
if (strcmp(retType, @encode(NSInteger)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
NSInteger result = 0;
[invocation getReturnValue:&result];
return @(result);
}
... more see @encode type in Object-C
还需要考虑线程执行问题,以及同一组方法返回值执行完后才能开始下一个方法,所以并不是很有必要。
实现
最终我这样实现的:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface HCProxy : NSObject
- (void)addObject:(id)object;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (NSArray *)allObjects;
@end
NS_ASSUME_NONNULL_END
#import "HCProxy.h"
@interface HCProxy ()
@property (nonatomic, strong) NSPointerArray *weakArray;
@end
@implementation HCProxy
- (void)addObject:(id)object {
[self.weakArray addPointer:(__bridge void *)object];
}
- (void)removeObjectAtIndex:(NSUInteger)index; {
[self.weakArray removePointerAtIndex:index];
}
- (NSArray *)allObjects {
return self.weakArray.allObjects;
}
- (NSPointerArray *)weakArray {
if (!_weakArray) {
_weakArray = [NSPointerArray weakObjectsPointerArray];
}
return _weakArray;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
for (NSObject* obj in self.weakArray) {
if (obj && ![obj isKindOfClass:[NSNull class]]) {
if ([obj respondsToSelector:aSelector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[obj performSelector:aSelector withObject:nil];
#pragma clang diagnostic pop
}
}
}
return nil;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
void *null = NULL;
[invocation setReturnValue:&null];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}
@end
在ViewController中测试
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
HCProxy *proxy;
//@autoreleasepool {
Person *person = [Person new];
dog *d = [dog new];
proxy = [[HCProxy alloc] init];
[proxy addObject:person];
[proxy addObject:d];
//}
[proxy performSelector:@selector(call)];
NSLog(@"----");
}
结果如下:
2020-04-19 00:33:32.540234+0800 HCProxy[1182:6015706] -[Person call]
2020-04-19 00:33:32.540443+0800 HCProxy[1182:6015706] -[dog call]
2020-04-19 00:33:32.540619+0800 HCProxy[1182:6015706] ----
2020-04-19 00:33:32.560592+0800 HCProxy[1182:6015706] -[dog dealloc]
2020-04-19 00:33:32.560761+0800 HCProxy[1182:6015706] -[Person dealloc]
链接:https://pan.baidu.com/s/1TVDn9EN1bHvSYOzW0vufSg
密码:yz3l
生活中有着太多无奈,但是某一天你跳出这个圈,你就发现,只需要你静下心来处理,生活会井井有条