第一篇Objective的文章,第一次使用Markdown來寫。
頁面?zhèn)髦档姆椒ㄓ泻芏啵埠艹S玫?,Delegate/NSNotification/Block/NSUserDefault/單例,等等。
一項一項增加,先寫最常用的委托傳值,也就是Delegate,老師講的方法。(TryAttack,這個無聊的時候玩這個。)
委托傳值 Delegate
協(xié)議方法是一種非常常用的傳值方法,只要在協(xié)議中聲明一個協(xié)議方法,然后兩個類一個作為委托方一個作為遵守方來調(diào)用和實現(xiàn)方法就可以實現(xiàn)傳值。十分高效而且針對性很強(qiáng)。
我們建立完Text Field元件和程式碼的關(guān)聯(lián)后,完成頁面1UIViewController 的 Button 拖拽到 SecndViewController ,並且在Custom Class 的Class中設(shè)定第二個ViewController 為 SecndViewController (即客制化所對應(yīng)的Class)。這樣就產(chǎn)生了 Storyboard Segue 的方法,選者Model作為連接,Storyboard Segue 就會自動連接到UIViewController。
如果想要使用不同的換頁效果,可以在 Storyboard Segue 中的 Transition 屬性做修改。
接下來我們就來實作委托傳值的方法,首先來考慮如何往 SecndViewController 進(jìn)行傳值。
- 透過 Storyboard Segue 傳值,在頁面 2
SecndViewController的 UIViewController class 里設(shè)置一個NSString的變數(shù),它用來接收由頁面 1 透過 Storyboard Segue 所傳過來的值,程式碼如下。
@property (strong) NSString* strAttackPower;
之后在SecndViewController.h的viewDidLoad函式里我們將 string 的值指定給 pAttackResult,此時頁面 2 加載時就會把 pAttackResult的內(nèi)容設(shè)成 Storyboard Segue 所傳送過來的值。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
int iDefensValue = rand()%10;
iScore = [strAttackPower intValue] - iDefensValue;
if ( iScore > 0 ){
pAttackResult.text = [NSString stringWithFormat: @"攻擊造成%d傷害,得分%d", iScore, iScore];
}else {
pAttackResult.text = @"攻擊被防御";
iScore = 0;
}
}
接著回到頁面 1 的 UIViewController class 里,新增一個內(nèi)建的函式 prepareForSegue,至此我們完成透過 Storyboard Segue 傳值的方法。
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
id pNextPage = segue.destinationViewController;
[pNextPage setValue:[NSString stringWithFormat: @"%d", 1+rand()%10 ] forKey: @"strAttackPower"];
[pNextPage setValue:self forKey:@"delegate"];
}
在ViewController 切換(Segue)之前會呼叫上面的方法,至此我們完成了向下一層的傳值。
- 關(guān)鍵點(diǎn)在
setValue: forKey:下面看一下定義:
setValue: forKey:
setValue: forKey:中value能夠為nil,但是當(dāng)value為nil的時候,會自動調(diào)用removeObject: forKey:方法,key的參數(shù)只能夠是NSString類型,而對應(yīng)的setObject: forKey:的可以是任何類型
2.返回先前頁面的方法
使用 dismissModalViewControllerAnimated: 方法,或是 dismissViewControllerAnimated:completion: 方法來解散SecndViewController,并返回先前的頁面。
- (IBAction)goBack:(id)sender {
if ([self.delegate respondsToSelector:@selector(incrementScore:from:)]) {
[self.delegate incrementScore:iScore from:self];
}
[self dismissViewControllerAnimated:YES completion: ^{}];
}
3.由上面的兩步我們已經(jīng)建立兩個可以互相切換的 UIViewController,一個是透過 Storyboard Segue 來切換并且向下傳值,另一個則是使用 dismissViewControllerAnimated: 的方法來返回先前的 UIViewController。
接下來就是要解決的就是 SecndViewController 向上傳值的部分,也就是通過代理委托delegate,建立一個協(xié)定 @protocol 的方式。
將此分為兩個角色五個步驟。
委托者:
1.聲明delegate屬性。2.調(diào)用協(xié)議方法。
被委托者:
1.遵守協(xié)議。2.設(shè)定為被委托者。3.覆寫協(xié)議方法。
委托者 SecndViewController
1.聲明delegate屬性:首先在頁面 2 的 UIViewController class,建立一個協(xié)定 incrementScoreDelegate,并且定義其內(nèi)部的方法 goBack:,接著宣告一個采用此協(xié)定的物件 delegate,其程式碼如下。
//建立一個協(xié)定
@protocol incrementScoreDelegate;
@interface SecndViewController : UIViewController
@property (strong, nonatomic) IBOutlet UITextField *pAttackResult;
@property (strong) NSString* strAttackPower;
//協(xié)定中的方法
@property (weak) id<incrementScoreDelegate> delegate;
- (IBAction)goBack:(id)sender;
@end
//宣告一個採用incrementScoreDelegate 協(xié)定的物件
@protocol incrementScoreDelegate <NSObject>
- (void) incrementScore: (int) score from:(SecndViewController* ) page;
@end
2.調(diào)用協(xié)議方法: 也就是上面第二點(diǎn)2.返回先前頁面的方法,要呼叫協(xié)定必須寫在按鈕事件中。當(dāng)我們按下頁面2的按鈕的時候,就會呼叫采用incrementScoreDelegate的Class,因此Class必須實作協(xié)定內(nèi)的方法。
被委托者 UIViewController
1.遵守協(xié)議:採用協(xié)定的方式是在 @interface 區(qū)段的地方加上 <協(xié)定名稱> 的程式碼,由于此協(xié)定是寫在其他的 class 中,所以在採用協(xié)定之前要先引用它,以下是頁面1的 UIViewController class.h 檔。
//引用持有incrementScoreDelegate協(xié)定的class
#import "SecndViewController.h"
//採用協(xié)定
@interface ViewController : UIViewController <incrementScoreDelegate>
2.設(shè)定為被委托者:在 .m 檔中實作協(xié)定內(nèi)的 incrementScore: 方法函式。
- (void) incrementScore:(int)score from:(SecndViewController *)page {
iTotalScore = iTotalScore + score;
pScoreBoardLable.text = [NSString stringWithFormat:@"Score: %d", iTotalScore];
}
3.覆寫協(xié)議方法: 如果忽略此步驟,頁面2里的 delegate 參數(shù)在呼叫 goBack 方法時,并不會知道是哪個 class實作了它的方法,因此參數(shù)也無法由頁面2SecndViewController傳遞至頁面1UIViewController。
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
//將 pNextPage 設(shè)定成Storyboard Segue的目標(biāo)UIViewController
id pNextPage = segue.destinationViewController;
//將值透過Storyboard Segue帶給頁面2 `pNextPage` 的string變數(shù)
[pNextPage setValue:[NSString stringWithFormat: @"%d", 1+rand()%10 ] forKey: @"strAttackPower"];
//將delegate設(shè)成自己(指定自己為代理)
[pNextPage setValue:self forKey:@"delegate"];
}
協(xié)議傳值的五步,最重要的是思考清楚,誰作為委托者,誰遵守協(xié)議,然后用這五個步驟來進(jìn)行實作。
