在iOS中,所有的UIControl標準控制元件使用到最普遍最傳統的執行方法的方式就是Target-Action,中文一般稱作目標-動作,是比較常用的一種設計模式。它的主要思想就是,在物件產生某個事件的特定時刻,給一個物件傳送一個訊息。就好像說『當talisk即將吃早飯的時候,swain去煎個蛋』。
其實Target-Action是很好用很方便的一個模式,但其最致命的一個缺點就是傳值很麻煩,本文總結下這種模式的傳值方式,並給出我認為最好的一個傳值方式。
給物件加tag
這是最簡單的一個方式,tag
是一個無符號整型值,貫穿於所有UIKit控制元件,給控制元件加上tag
,在action方法裡可以取到sender
,對sender
做強制型別轉換即可拿到tag
。
1 |
[self.datePicker addTarget:self action:@selector(dateChange:) forControlEvents:UIControlEventValueChanged]; |
1 2 3 4 5 |
- (void)dateChange:(id)sender { if (((UIDatePicker *)sender).tag) { NSLog(@"tag0"); } } |
由於tag
是個無符號整型數值,也僅僅能傳遞一些簡單資料。
sender
就是發起行為的物件,就像上面這段程式碼所寫,當datePicker
的值發生變化的時候,呼叫self
的dateChange:
方法,這個方法預設引數就是sender
。
給父類做category
通過category給父類加上一些方法,使子類物件能夠攜帶一些資料,這樣對於開發者來說就很自由了。
1 2 3 4 5 6 7 |
#import <Foundation/Foundation.h> @interface NSObject (Extension) @property (nonatomic,retain)NSDictionary *userInfo; @end |
在標頭檔案中,註明category和名稱,加上我們需要使用的資料的property。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#import "NSObject+Extension.h" #import <objc/runtime.h> @implementation NSObject (Extension) - (void)setUserInfo:(NSDictionary *)_userInfo { objc_setAssociatedObject(self, @"userInfo", _userInfo, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (id)userInfo { return objc_getAssociatedObject(self, @"userInfo"); } @end |
在實現檔案中,要用到Objective-C的Runtime黑魔法了,通過使用objc_getAssociatedObject
和objc_setAssociatedObject
兩個執行時函式的使用,動態地向NSObject
根類中新增了屬性,這樣,只要是繼承自NSObject
並且引用了這個Category的地方,我們都可以給物件新增userInfo這個屬性,意味著我們想傳遞什麼就可以傳遞什麼了。
在寫完這個Category後,我們在需要傳值的地方,給物件設定好userInfo,即可。
1 2 |
[self.datePicker addTarget:self action:@selector(dateChange:) forControlEvents:UIControlEventValueChanged]; [self.datePicker setUserInfo:@{@"from": [NSDate date], @"to": [NSDate date]}]; |
1 2 3 |
- (void)dateChange:(id)sender { NSLog(@"%@", ((UIDatePicker *)sender).userInfo); } |