在面向?qū)ο箝_發(fā)中,經(jīng)常遇到多個(gè)類間傳值,總結(jié)起來(lái)即正向傳值(A—>B)(屬性傳值),反向傳值(A<—B)(利用對(duì)象,使用TargetAction,使用協(xié)議代理,使用系統(tǒng)自帶的Block,使用自定義Block),雙向傳值(A<—>B)(使用NSUserDefaults進(jìn)行數(shù)據(jù)傳值,使用系統(tǒng)的UIApplication單例進(jìn)行傳值,使用自己的單例類進(jìn)行傳值,使用通知中心NSNotificationCenter進(jìn)行傳值,使用KVC進(jìn)行傳值)。
1.正向傳值
屬性傳值
在B類中定義屬性用于接收A類傳來(lái)的數(shù)據(jù)
2.反向傳值(回調(diào))
1)利用對(duì)象反向傳值
將A類對(duì)象定義成B類的屬性進(jìn)行傳值
如,通過(guò)KGSubViewController(B)修改 KGRootViewController(A)的Label
KGRootViewController
//在KGRootViewController中定義函數(shù)接收返回的數(shù)據(jù)
-(void)backValue:(NSString *)string color:(UIColor *)color
{
//將參數(shù)的值賦給label
label.text = string;
//將顏色賦給賦給lable的字體顏色
label.textColor = color;
}
界面跳轉(zhuǎn)至KGSubViewController,并將KGRootViewController對(duì)象傳到KGSubViewController中
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KGSubViewController * svc = [[KGSubViewController alloc]init];
//讓B持有A
svc.rvc = self;
[self presentViewController:svc animated:YES completion:nil];
}
KGSubViewController
//創(chuàng)建一個(gè)Root對(duì)象
@property(nonatomic,retain) KGRootViewController * rvc;
//在銷毀之前,做一些回傳數(shù)據(jù)的事
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.rvc backValue:tf.text color:[UIColor redColor]];
[self dismissViewControllerAnimated:YES completion:nil];
}
2)使用TargetAction反向傳值
通過(guò)指定回傳方法和回傳對(duì)象進(jìn)行傳值
仍以上例為例,實(shí)現(xiàn)方法為:
KGRootViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KGSubViewController * svc = [[KGSubViewController alloc]init];
//將回傳對(duì)象進(jìn)行指定
svc.target = self; //這里的self是指rootviewcontrller
//將回傳方法,進(jìn)行指定
svc.selector = @selector(backValue:);
[self presentViewController:svc animated:YES completion:nil];
}
-(void)backValue:(NSString *)string
{
//回傳數(shù)據(jù)方法
label.text = string;
}
KGSubViewController
//在這里定義兩個(gè)屬性,用來(lái)接收目標(biāo)和方法,用來(lái)進(jìn)行反向傳值
//接收要回傳的對(duì)象
@property(nonatomic,retain) id target;
//接收回傳數(shù)據(jù)的方法
@property(nonatomic,assign) SEL selector;
//在銷毀之前,將數(shù)據(jù)回傳回去
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//利用保存的target 和 action 來(lái)進(jìn)行回傳
if ([self.target respondsToSelector:self.selector]) {
[self.target performSelector:self.selector withObject:tf.text];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
3)使用協(xié)議代理反向傳值
協(xié)議代理是回調(diào)中常用的方法,顧名思義,把某個(gè)對(duì)象要做的事情委托給別的對(duì)象去做。那么別的對(duì)象就是這個(gè)對(duì)象的代理,代理它來(lái)打理要做的事情。使用協(xié)議代理不僅可以正向傳值,亦可反向傳值。在使用中,需要注意哪個(gè)類是委托方,哪個(gè)類是代理方。總之:誰(shuí)傳值誰(shuí)是委托方
如,通過(guò)KGSubViewController改變KGRootViewController中l(wèi)abel值
在KGSubViewController頁(yè)面里,制定一個(gè)協(xié)議
@protocol BackValue <NSObject>
//回傳數(shù)據(jù)的協(xié)議方法
-(void)backValue:(NSString *)string;
@end
@property(nonatomic,retain) id < BackValue > delegate;
在KGSubViewController使代理方實(shí)現(xiàn)方法
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//代理方實(shí)現(xiàn)協(xié)議中的方法
[self.delegate backValue:tf.text];
[self dismissViewControllerAnimated:YES completion:nil];
}
在KGRootViewController中實(shí)現(xiàn)協(xié)議 <BackValue>
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KGSubViewController * svc = [[KGSubViewController alloc]init];
//讓A同意B所提出的協(xié)議條件
svc.delegate = self;
[self presentViewController:svc animated:YES completion:nil];
}
//實(shí)現(xiàn)協(xié)議 方法
-(void)backValue:(NSString *)string
{
label.text = string;
}
4)使用系統(tǒng)自帶的Block進(jìn)行反向傳值
block是代碼塊的對(duì)象,類似函數(shù)指針,調(diào)用block如同調(diào)用代碼塊中的代碼,利用block可以實(shí)現(xiàn)回調(diào)。
在系統(tǒng)提供方法中,有很多使用block方法,如界面跳轉(zhuǎn)presentViewController時(shí)
將KGRootViewController中l(wèi)abel.text值傳給KGSubViewController textField.text
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KGSubViewController * svc = [[KGSubViewController alloc]init];
svc.rvc = self;
//OC中,block用來(lái)去指向一個(gè)匿名的語(yǔ)句塊,從而可以當(dāng)成函數(shù)還調(diào)用該語(yǔ)句塊
//這個(gè)方法的第三個(gè)參數(shù)是一個(gè)block,意思說(shuō),當(dāng)彈出來(lái)的svc顯示完成后,執(zhí)行block里的內(nèi)容
[self presentViewController:svc animated:YES completion:^{
//正向傳值
svc.textField.text = self.label.text;
}];
}
將KGSubViewController textField.text值傳給 KGRootViewController中l(wèi)abel.text
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self dismissViewControllerAnimated:YES completion:^{
self.rvc.label.text = self.textField.text;
}];
}
5)使用自定義Block反向傳值
KGSubViewController
//定義一個(gè)block的屬性
@property(nonatomic,copy)void (^block)(NSString *);
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//執(zhí)行block
self.block(tf.text);
[self dismissViewControllerAnimated:YES completion:nil];
}
KGRootViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KGSubViewController * svc = [[KGSubViewController alloc]init];
//給block賦值,做用是讓svc知道block指向的代碼塊的功能
svc.block = ^(NSString * string){
label.text = string;
};
[self presentViewController:svc animated:YES completion:nil];
}
3.雙向產(chǎn)值
1)使用NSUserDefaults進(jìn)行數(shù)據(jù)傳值
NSUserDefaults紀(jì)錄本地一些輕量級(jí)的數(shù)據(jù),是單例類。其通過(guò)userDefaults對(duì)象來(lái)將選中按鈕的索引給保存到NSUserDefaults的plist文件中。這個(gè)文件實(shí)際上是一個(gè)plist文件,在沙盒中的/Library/Preferences/NSUserDefaults.plist 這個(gè)位置
當(dāng)KGSubViewController調(diào)用viewWillAppear時(shí)讀取沙盒內(nèi)容
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//獲取NSUserDefaults文件,讀取里面內(nèi)容,來(lái)決定讓哪一個(gè)按鈕進(jìn)行選中
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
//通過(guò)存的時(shí)候的key值來(lái)進(jìn)行取值
NSString * value = (NSString *)[ud objectForKey:@"ButtonIndex"];
//計(jì)算出按鈕的tag值
int buttonIndex = 1000 + value.intValue;
//利用tag值取到按鈕
UIButton * button = (UIButton *)[self.view viewWithTag:buttonIndex];
button.selected = YES;
}
KGRootViewController
點(diǎn)擊button將點(diǎn)擊按鈕的索引存入沙盒中
-(void)buttonClick:(UIButton *)button
{
for (int i = 1;i<6; i++) {
UIButton * btn = (UIButton *)[self.view viewWithTag:1000+i];
if (btn.selected == YES) {
btn.selected = NO;
}
}
button.selected = YES;
//將每次點(diǎn)擊選中的按鈕索引給存起來(lái)
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
NSLog(@"%@",[NSBundle mainBundle]);
//通過(guò)userDefaults對(duì)象來(lái)將選中按鈕的索引給保存到NSUserDefaults的plist文件中
//這個(gè)文件實(shí)際上是一個(gè)plist文件,在沙盒中的/Library/Preferences/NSUserDefaults.plist 這個(gè)位置
[userDefaults setObject:[NSString stringWithFormat:@"%d",button.tag - 1000] forKey:@"ButtonIndex"];
//回寫文件
[userDefaults synchronize]; //synchronize:使同步,同時(shí)發(fā)生
}
KGRootViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//獲取NSUserDefaults文件,讀取里面內(nèi)容,來(lái)決定讓哪一個(gè)按鈕進(jìn)行選中
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
//通過(guò)存的時(shí)候的key值來(lái)進(jìn)行取值
NSString * value = (NSString *)[ud objectForKey:@"ButtonIndex"];
label.text = [NSString stringWithFormat:@"上次按下的是第 %@ 個(gè)按鈕",value];
}
2)使用系統(tǒng)的UIApplication單例進(jìn)行傳值
單例類在程序中只創(chuàng)建一次實(shí)例對(duì)象,利用這個(gè)特點(diǎn)可以進(jìn)行傳值。在iOS開發(fā)中,UIApplication就是個(gè)單例類,利用他可實(shí)現(xiàn)傳值。
在UIApplication定義存儲(chǔ)內(nèi)容
//創(chuàng)建一個(gè)公共數(shù)組,用來(lái)存放數(shù)據(jù),
@property(nonatomic,retain) NSMutableArray * array;
在相應(yīng)ViewController中使用
//應(yīng)該去利用系統(tǒng)的UIApplication這個(gè)單例來(lái)獲取系統(tǒng)已經(jīng)創(chuàng)建好的那個(gè)AppDelegate里的對(duì)象
//這是一個(gè)單例 對(duì)象,在整個(gè)程序中,只有一個(gè)唯一的實(shí)例存在
UIApplication * application = [UIApplication sharedApplication];
//通過(guò)這個(gè)單例對(duì)象來(lái)找到它持有的AppDelegate對(duì)象
KGAppDelegate * appDelegate = application.delegate;
//通過(guò)appDelegate對(duì)象拿到他的數(shù)組
[appDelegate.array addObject:self.title];
3)使用自己的單例類進(jìn)行傳值
除了使用系統(tǒng)自帶的單例類外,還可以使用自定義單例類用來(lái)傳值
自定義單例類KGMyApplication
//為application類,添加一個(gè)屬性,用來(lái)接收MyAppDelegate對(duì)象
@property(nonatomic,retain) KGMyAppDelegate * delegate;
//使用這個(gè)方法來(lái)實(shí)例一個(gè)單例對(duì)象
+(KGMyApplication *)sharedMyApplication;
+(KGMyApplication *)sharedMyApplication
{
static KGMyApplication * obj = nil;
if (!obj) {
//給obj創(chuàng)建單例對(duì)象
obj = [[KGMyApplication alloc]init];
//給單例對(duì)象的delegate屬性賦值
obj.delegate = [[KGMyAppDelegate alloc]init];
}
return obj;
}
定義KGMyAppDelegate類保存數(shù)據(jù)
//這個(gè)類不是一個(gè)單例類,但是,需要在這里保存數(shù)據(jù)
@property(nonatomic,retain)NSMutableArray * array;
在相應(yīng)ViewController中使用
//首先獲取MyApplication的單例對(duì)象
KGMyApplication * app = [KGMyApplication sharedMyApplication];
//通過(guò)這個(gè)單例對(duì)象里的delegate屬性來(lái)獲取MyAppDelegate對(duì)象
KGMyAppDelegate * appDelegate = app.delegate;
//獲取MyAppDelegate里的數(shù)組
NSMutableArray * array = [appDelegate array];
static int n = 0;
[array addObject:[NSString stringWithFormat:@"VC1-%d",n++]];
4)使用通知中心NSNotificationCenter進(jìn)行傳值
通知由通知中心發(fā)送,通知中心在整個(gè)工程中只有一個(gè)。通知中心可以發(fā)送多條消息,可以在整個(gè)工程中的任何位置接收消息,通過(guò)通知中心的名稱區(qū)分消息。
一個(gè)簡(jiǎn)單的應(yīng)用,從界面2中發(fā)送通知,界面1中接收
KGFirstViewController
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomeThing:) name:@"xiaoxi" object:nil];
- (void)doSomeThing:(NSNotification *)noti
{
NSLog(@"收到了");
label.text = [noti.userInfo objectForKey:@"key"];
}
KGSecondViewController
NSNotification *noti = [[NSNotification alloc]initWithName:@"xiaoxi" object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@", btn.titleLabel.text],@"key", nil]];
// 發(fā)送
[[NSNotificationCenter defaultCenter] postNotification:noti];
類間傳值是編程時(shí)最常用的方法,也是最基礎(chǔ)的語(yǔ)法。在程序中使用不同的方法可以使的程序編的更加靈活。除以上方法外,還有KVC等方法,將在后續(xù)詳解。
歡迎各位指教