一个应用 ,一般都会有很多对象,对象与对象之间避免不了进行消息传递。说到消息传递,肯定是相互的,即由A传到B,也可以由B传的A。
iOS下,有以下消息传递方式:
- 属性(Get/Set)
- 方法(Public)
- KVO
- Target-Action
- 通知(NSNotification)
- 代理(DataSource/Delegate,其实是Protocol)
- Block
这篇文章主要介绍Target-Action,其他方法这里暂不介绍。
先来看以下Target-Action在系统提供的Framework中都有哪些使用。
- UIKit.framework
有UIControl以及其子类(比如UIButton、UISwitch等)
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0.0, 0.0, 100.0, 50.0);
[btn addTarget:self action:@selector(clickButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
- Foundation.framework
有NSTimer
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:NO];
上面提及到的示例,相信大家都有所了解,这里不多介绍,直接提需求,如果我们想自己实现Target-Action该如何做?
直接上代码
方案1:
#import <Foundation/Foundation.h>
//
@interface Manager : NSObject
//
-(void)addTarget:(id)aTarget selector:(SEL)aSelector;
@end
#import "Manager.h"
//
@interface Manager ()
//
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@end
//
@implementation Manager
//
-(id)init {
self = [super init];
if (self) {
//
}
return self;
}
//
(void)addTarget:(id)aTarget selector:(SEL)aSelector {
_target = aTarget;
_selector = aSelector;
}
@end
方案2
#import <Foundation/Foundation.h>
//
@interface Manager : NSObject
//
-(void)addTarget:(id)aTarget selector:(SEL)aSelector forEvent:(NSInteger)aEvent;
-(void)removeTarget:(id)aTarget forEvent:(NSInteger)aEvent;
@end
#import "Manager.h"
//
@interface Manager ()
//
@property (nonatomic, strong) NSMutableDictionary *targetDict;
@end
//
@implementation Manager
//
-(id)init {
self = [super init];
if (self) {
_targetDict = [[NSMutableDictionary alloc] initWithCapacity:0];
}
return self;
}
//
-(void)addTarget:(id)aTarget selector:(SEL)aSelector forEvent:(NSInteger)aEvent {
NSString *key = [NSString stringWithFormat:@"%zd",aEvent];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:0];
[dict setValue:aTarget forKey:@"target"];
[dict setValue:NSStringFromSelector(aSelector) forKey:@"action"];
[_targetDict setValue:dict forKey:key];
}
//
-(void)removeTarget:(id)aTarget forEvent:(NSInteger)aEvent {
NSString *key = [NSString stringWithFormat:@"%zd",aEvent];
if ([[_targetDict allKeys] containsObject:key]) {
[_targetDict removeObjectForKey:key];
}
}
@end
方案3
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface WeakProxy : NSProxy
//
@property (nullable, nonatomic, weak, readonly) id target;
//
-(instancetype)initWithTarget:(id)target;
+(instancetype)proxyWithTarget:(id)target;
NS_ASSUME_NONNULL_END
@end
#import "WeakProxy.h"
@implementation WeakProxy
- (instancetype)initWithTarget:(id)target {
_target = target;
return self;
}
+ (instancetype)proxyWithTarget:(id)target {
return [[WeakProxy alloc] initWithTarget:target];
}
- (id)forwardingTargetForSelector:(SEL)selector {
return _target;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
void *null = NULL;
[invocation setReturnValue:&null];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return [_target respondsToSelector:aSelector];
}
@end
#import <Foundation/Foundation.h>
@interface Manager : NSObject
- (void)addTarget:(id)aTarget selector:(SEL)aSelector forEvent:(NSInteger)aEvent;
- (void)removeTarget:(id)aTarget forEvent:(NSInteger)aEvent;
@end
#import "Manager.h"
#import "WeakProxy.h"
@interface Manager ()
@property (nonatomic, strong) NSMutableDictionary *targetDict;
@end
@implementation Manager
- (id)init {
self = [super init];
if (self) {
_targetDict = [[NSMutableDictionary alloc] initWithCapacity:0];
}
return self;
}
- (void)addTarget:(id)aTarget selector:(SEL)aSelector forEvent:(NSInteger)aEvent {
WeakProxy *proxy = [WeakProxy proxyWithTarget:aTarget];
NSString *key = [NSString stringWithFormat:@"%zd",aEvent];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:0];
[dict setValue:proxy forKey:@"target"];
[dict setValue:NSStringFromSelector(aSelector) forKey:@"action"];
[_targetDict setValue:dict forKey:key];
}
- (void)removeTarget:(id)aTarget forEvent:(NSInteger)aEvent {
NSString *key = [NSString stringWithFormat:@"%zd",aEvent];
if ([[_targetDict allKeys] containsObject:key]) {
[_targetDict removeObjectForKey:key];
}
}
@end
好啦,到这我想到的解决方案就是这些了。有兴趣的可以比较方案1、2、3的区别!!