一、目錄
- 屬性 傳值
- 單例 傳值
- block傳值
- 代理 傳值
- 總結
- 個人使用心得
- 代碼下載地址:https://github.com/ChenZeBin/SendValue
二、掌握四大傳值前提
1.掌握push跳轉 相關文章鏈接:http://www.jianshu.com/p/46f693f761a1
2.掌握單例模式
3.掌握block
4.掌握代理
三、介紹
1、屬性傳值
(1)、介紹:
比如A視圖要給B視圖傳值字符“abc”
1,B視圖就聲明一個屬性NSSTring來接受字符abc
2,A視圖中new一個B控制器,B.NSString = “abc”
3,這樣就賦值過去了
(2)、代碼:
// B視圖的.h文件
@property (nonatomic,copy) NSString *propertySendString;
// 用來接受A視圖傳遞過來的數據
// A視圖的.m文件
Delegate *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
vc.propertySendString = @"屬性傳值";
[self.navigationController pushViewController:vc animated:YES];
(3)、注意:
在A視圖裏面new了B視圖,這時候跳轉到B視圖,一定一定一定要把這個new的視圖push過去,不然如果是故事版脫線跳轉的話,跳轉過來的就不是這個new的B控制器了,那麼傳遞肯定是失敗的
2、單例傳值
(1)、介紹:
單例就是整個APP只有一個對象,比如我把A類設爲單例,那麼我new的A類對象都是同一樣,不會出現第二個的,這樣我給A類中的一個變量賦值,那麼我在其他視圖想要用的時候,我就只需要new這個單例對象去拿這個變量的值就可以了
(2)、代碼
// 創建一個單例類 這個類的.h文件
#import <Foundation/Foundation.h>
@interface SingleTon : NSObject
// 傳值的屬性
@property (nonatomic,copy) NSString *passValue;
// 創建單例 (單例的命名,shared+類名)
+ (SingleTon *)sharedSingleTom;
@end
// 這個類的.m文件
#import "SingleTon.h"
@implementation SingleTon
// 以下是創建單例的方法,這是嚴格的單例,所以代碼偏多
// 嚴格是創建單例步驟
static SingleTon *singleTon;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleTon = [super allocWithZone:zone];
});
return singleTon;
}
+ (SingleTon *)sharedSingleTom {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleTon = [[SingleTon alloc] init];
});
return singleTon;
}
-(id)copyWithZone:(NSZone *)zone{
return singleTon;
}
@end
// 比如我A界面想把abc傳到B界面,
// 那麼我這個單例類就是傳值的中間介質
// 以下代碼就是給單例的變量賦值(賦我要傳的值)
// 比如我在A界面裏給單例變量賦值,那麼接下來我在B界面裏,創建這個單例,然後直接調用這個單例變量,這個變量就是abc的值了
SingleTon *singleTon = [SingleTon sharedSingleTom];
singleTon.passValue = @"單例傳值";
3、block傳值
(1)、介紹
可以向任何方向傳值
比如我A類中有個值要傳出來,那麼我就在A類寫一個類方法,類方法的參數是block,然後這個block的參數是我要傳的值
這樣我在B類就可以用直接用A類調用這個類方法,然後這個類方法的block回調裏就會帶一個參數,這個參數是帶有值的,值就是從A類block參數帶出來的
(2)、代碼
// A類的.h文件
#import <Foundation/Foundation.h>
// 定義一個閉包(block),然後參數是字符串
typedef void (^sentValue)(NSString *str);
@interface Block : NSObject
// 定義一個類方法,參數是這個閉包
+ (void)sentValueClick:(sentValue)_sentBlock ;
@end
// A類的.m文件
#import "Block.h"
@implementation Block
// 實現.h文件中定義的類方法
+ (void)sentValueClick:(sentValue)_sentBlock {
// 這個給這個閉包傳的參數“block傳值”就是你要傳的值了
_sentBlock(@"block傳值");
}
@end
// 你想在哪裏拿到這個值,就在哪裏調用這個方法,這個str參數就是傳出來的值
[Block sentValueClick:^(NSString *str) {
NSLog(@"block:%@",str);
}];
4、代理傳值
(1)、介紹:
代理傳值一般用於後向前傳值
比如我A點擊跳轉到B界面,然後想把B界面的值傳遞到A界面,並且跳轉回A界面
那麼我就在B界面寫一個代理和代理方法,然後再B界面視圖消失的方法裏面調用這個代理方法,這時候由於你已經設置A界面爲B的代理對象了,所以在B界面快消失的時候調用代理方法,其實是A界面調用了代理方法,所以這時候就可以把我要傳遞的值傳遞過去(有點難理解,具體看下代碼)
(2)、代碼
// B界面.h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol SentValueDelegate <NSObject>
@optional
- (void)sentValueClicked:(NSString *)str;
@end
@interface Delegate : UIViewController
@property (nonatomic,weak) id <SentValueDelegate> delegate;
@property (nonatomic,copy) NSString *propertySendString;
@end
//B界面.m文件
// 視圖即將消失會自動調用的方法
- (void)viewWillDisappear:(BOOL)animated {
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
[self.delegate sentValueClicked:@"代理傳值"];
}
}
// A界面的.m文件
// 點擊按鈕跳轉到第二個頁面 代理傳值(後向前傳值)
- (IBAction)pushClicked:(UIButton *)sender {
Delegate *delegateVC = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
delegateVC.delegate = self;
[self.navigationController pushViewController:delegateVC animated:YES];
}
// 實現代理的方法(這個方法包含着一個參數,這個參數就是從B頁面傳遞過來的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
(3)、補充說明
對於這個代理,確實有點難理解,這裏我說下執行的順序
首先是A類的.m文件
我點擊按鈕,跳轉到B界面,這時候我點擊按鈕就會來到按鈕的監聽方法,在這個方法裏面new一個B控制器,然後這時候就要設置B的代理爲A類,因爲這時候要先設置好,等下B類調用代理方法纔會來到這裏
// A界面的.m文件
// 點擊按鈕跳轉到第二個頁面 代理傳值(後向前傳值)
- (IBAction)pushClicked:(UIButton *)sender {
Delegate *delegateVC = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
delegateVC.delegate = self;
[self.navigationController pushViewController:delegateVC animated:YES];
}
// 實現代理的方法(這個方法包含着一個參數,這個參數就是從B頁面傳遞過來的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
跳轉到B類後,在B類快要消失的方法寫以下代碼
代碼的說明:如果delegate這個代理屬性響應了這個方法
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
如果響應了就執行以下代碼,那麼這裏就是關鍵了
我剛纔是A類實現代理方法,就是響應就這個方法
剛纔我在A類把delegate = A類控制器
(設置了代理),
所以這時候self.delegate
是等於A類控制器的self
那麼以下的代碼就相當於[A類的self 調用sentValueClicked]
[self.delegate sentValueClicked:@"代理傳值"];
那麼這時候,程序就會來到A類實現的代理方法,
看以下代碼,這時候,這個方法的參數str就是
[self.delegate sentValueClicked:@"代理傳值"];
裏面的”代理傳值”
// 實現代理的方法(這個方法包含着一個參數,這個參數就是從B頁面傳遞過來的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
以上就是代理傳值理解的關鍵地方,如果這個可以理解好,那麼代理是怎麼執行的也就可以理解好了
- (void)viewWillDisappear:(BOOL)animated {
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
[self.delegate sentValueClicked:@"代理傳值"];
}
}
四、總結
屬性 傳值 : 前向後
單例 傳值 : 任何方向
主要思想:單例做爲一箇中介block傳值: 任何方向
主要思想:哪個類要把值傳出來,哪個類就寫閉包(block),然後自動類方法+閉包參數的方法,把參數傳出來單例 傳值: 後向前
主要思想:哪個類需要把值傳出來,就在哪個類寫一個代理,然後想要獲取到這個值的話,那麼就設置自己爲這個類的代理對象,然後去實現它的代理方法,通過這個方法的參數拿到值
五、個人使用心得
最簡單的方式:
屬性傳值,但是侷限在前向後,爲什麼呢?
因爲我A類傳值給B類,這裏最主要的關鍵實現是,在A類中new一個B類,並且把我要傳的值賦值給B類的接受變量,然後把B類的對象push到B界面
,這時候在B類用self.接受變量
就可以拿到值了
其實,這裏實現的關鍵,就是B類的對象
在A類中new B類的對象,進行賦值,在B界面調用self也是這個B類對象,也就是說這是同一個對象,同一塊內存空間的,所以,理所當然可以賦值,然後傳值過去
所以大概知道爲什麼只能前向後了把,因爲這個實現的關鍵就是要控制同一個B類對象,如果我是後向前,那麼我B類裏面,我就得new一個A類對象,但是如果我是用pop
是沒辦法把A對象傳遞過去的,也就是說我這時候回到A界面又重新new 了一個A對象,所以傳值失敗的
最喜歡的方式:
block傳值:因爲這個block可以向任何地方傳值,步驟又少
#使用最多的方式:
block傳值和屬性傳值,如果是前向後我會用屬性傳值,其他情況大多是用block