目錄
1.屬性傳值(正向)
2.block傳值(反向)
3.通知傳值(反向)
4.協(xié)議傳值(反向)
5.單例傳值
1.屬性傳值(正向)





這樣就是正向的屬性傳值
2.block傳值(反向)
思路:
1.首先,創(chuàng)建兩個視圖控制器,在第一個視圖控制器中創(chuàng)建一個UILabel和一個UIButton,其中UILabel是為了顯示第二個視圖控制器傳過來的字符串,UIButton是為了push到第二個界面
2.第二個界面的只有一個UITextField,是為了輸入文字,當(dāng)輸入文字,并且返回第一個界面的時候,當(dāng)?shù)诙€視圖將要消失的時候,就將第二個界面上TextFiled中的文字傳給第一個界面,并且顯示在UILabel上
Demo:




效果:



補充:block相關(guān)知識點
http://www.itdecent.cn/p/f4fa7aeb2035
http://www.itdecent.cn/p/2aad46e3ea95
1.使用block時什么情況會發(fā)生引用循環(huán),如何解決?
一個對象中強引用了block,在block中又強引用了該對象,就會發(fā)射循環(huán)引用。
解決方法是將該對象使用__weak或者_(dá)_block修飾符修飾之后再在block中使用。
id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self該方法可以設(shè)置宏
id __block weakSelf = self;
或者將其中一方強制制空 xxx = nil。
檢測代碼中是否存在循環(huán)引用問題,可使用 Facebook 開源的一個檢測工具 FBRetainCycleDetector

block使用注意點:


3.通知傳值(反向)
Demo1:





效果:



Demo2:(帶數(shù)據(jù))
VC1:
1.發(fā)送通知(傳一個數(shù)據(jù)模型)
OrderListModel *nextModel = [self getNeedModel];//獲取下一個要接的乘客
OrderViewModel *orderViewModel = [[OrderViewModel alloc] initWithOrderModel:nextModel];
//通知訂單面板刷新
[[NSNotificationCenter defaultCenter] postNotificationName:@"GaodeNaviUpdateMapNaviPopupView" object:nil userInfo:@{@"orderViewModel":orderViewModel}];
VC2:
1.接收通知
- (void)viewDidLoad {
[super viewDidLoad];
//導(dǎo)航中更換終點導(dǎo)航刷新訂單面板
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(gaodeNaviUpdateMapNaviPopupView:) name:@"GaodeNaviUpdateMapNaviPopupView" object:nil];
}
2.通知回調(diào)方法
//通知回調(diào)方法-高德導(dǎo)航中改變終點刷新訂單面板
- (void)gaodeNaviUpdateMapNaviPopupView:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
OrderViewModel *orderViewModel = dic[@"orderViewModel"];
[orderViewModel refreshPrice];
self.mapNavigationPopupView.orderViewModel = orderViewModel;//更新數(shù)據(jù)
}
3.移除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
VC1:
1.發(fā)送通知(傳一個數(shù)據(jù))
[[NSNotificationCenter defaultCenter]postNotificationName:@"BBXListMapMergeNotification" object:nil userInfo:@{@"index":[NSString stringWithFormat:@"%ld",(long)i]}];
VC2:
1.接收通知
//任務(wù)列表-接送地圖標(biāo)題按鈕點擊的通知回調(diào)
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(BBXListMapMergeNotificationAction:) name:@"BBXListMapMergeNotification" object:nil];
2.通知回調(diào)方法
//任務(wù)列表-接送地圖標(biāo)題按鈕點擊的通知回調(diào)
- (void)BBXListMapMergeNotificationAction:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
NSString *index = dic[@"index"];
if ([index isEqualToString:@"1"]) {
self.currentTag = -1;
[self refreshEvent:NO];//網(wǎng)絡(luò)請求,刷新界面
self.tipsLabel.hidden = YES;
NSArray *tempArray = [NSArray arrayWithArray:self.orderArray];
for (OrderListModel *orderModel in tempArray) {
//有系統(tǒng)空單,移除系統(tǒng)空單數(shù)據(jù),顯示系統(tǒng)空單提示
if (orderModel.order_origin.intValue == 999) {
self.tipsLabel.hidden = NO;
self.isHaveEmptyOrder = YES;
}
}
}
}
//其他
//各界面彈框點詳情到任務(wù)列表通知回調(diào)
- (void)BBXListMapMergeNotificationSwitchAction:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
NSString *index = dic[@"index"];
if ([index isEqualToString:@"0"]) {
NSArray *vcs = [_titleScrollView subviews];
for (id view in vcs) {
if ([view isKindOfClass:[UIButton class]]) {
UIButton *btn = view;
if (btn.tag == index.intValue) {
[self titleClick:btn];
}
}
}
}
}
3.移除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Demo3:(通知的其他快捷寫法 - 可當(dāng)前VC發(fā)通知再收通知)



補充:通知相關(guān)知識點
NSNotification:
這個類可以理解為一個消息對象,其中有三個成員變量;observer是觀察者(一般在控制器中是self),它監(jiān)測通知中心是否有消息發(fā)送的那個對象
- name:這個成員變量是這個消息對象的唯一標(biāo)識,用于辨別消息對象,必須與需要發(fā)送通知的名字一致,否則通知無法到達(dá)
- object:這個成員變量定義一個對象,可以理解為針對某一個對象的消息;是通知關(guān)聯(lián)的對象,即誰發(fā)送的通知(看情況,有時傳的值很多,可以通過模型過渡...);也就是監(jiān)聽哪個對象發(fā)出的通知,如果使用"nil"值,代表監(jiān)聽所有通知
- userInfo:這個成員變量是一個字典,可以用其來進(jìn)行傳值;也就是傳遞的附加信息(通知的內(nèi)容)
NSNotificationCenter:
通信的特點是:為單例模式,可以實現(xiàn)一對多通信,每個應(yīng)用程序都會有一個默認(rèn)的通知中心;通知是觀察者(observer)模式的一種,結(jié)構(gòu)為:發(fā)布者->通知中心->接受者;
基本的使用過程:首先在需要接受數(shù)據(jù)的對象(或者控制器)注冊通知,在需要發(fā)布通信的對象中上傳通知



移除通知方法:

- 移除通知需要注意的坑:
了解:在了解控制器的生命周期之后,我們都知道viewWillAppear:方法是在控制器的view將要顯示的時候調(diào)用的,而viewWillDisappear:方法是在控制器的view將要隱藏的時候調(diào)用。很多時候我們根據(jù)自身需要將相關(guān)代碼邏輯添加到這兩個方法中。
- 小結(jié):
1、iOS7新增加了導(dǎo)航控制器側(cè)滑手勢,當(dāng)觸發(fā)側(cè)滑返回時,會調(diào)用系統(tǒng)的viewWillDisappear:方法,取消側(cè)滑返回時又會調(diào)用viewWillAppear:方法。
2、在做手勢和通知等一系列操作之時要分情況考慮:若通知和手勢是與UI相關(guān)的,如監(jiān)聽UITextField鍵盤的顯示和隱藏通知等應(yīng)該在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知;而與UI無關(guān)的通知和手勢,像自定義通知等,應(yīng)該在viewDidLoad等一次性方法中添加,在dealloc方法中釋放。
3、在viewWillAppear:、viewWillDisappear:、viewDidAppear:、viewDidDisappear:等類似于這種會多次調(diào)用的系統(tǒng)方法中添加代碼時,一定要多考慮業(yè)務(wù)邏輯,以免出現(xiàn)不必要的麻煩。
相關(guān)詳細(xì)講解鏈接:http://www.itdecent.cn/p/ea2aadef413d
注意點:
1.接受者和發(fā)布者的通知名字必須一致
2.接受者的對象中注冊使用完后應(yīng)該移除通知,一般在dealloc中移除
3.通知可以用于傳值,也可以用于其他地方;通知比較優(yōu)雅,耦合性低
4.協(xié)議傳值(反向)
Demo:




效果:



5.單例傳值
Demo:
單例類:
.h文件
#import <Foundation/Foundation.h>
@interface Datahandle : NSObject
@property (nonatomic, strong) NSString *passVolud;
+(instancetype)sharedHandle;// 單例方法
@end
.m文件
#import "Datahandle.h"
@implementation Datahandle
// 1.重寫init初始化方法(使用拋出異常的方式不讓調(diào)用)
-(instancetype)init {
@throw [NSException exceptionWithName:@"Datahandle" reason:@"不允許使用" userInfo:nil];
return self;
}
// 2.廢棄了系統(tǒng)的init方法,所以自己寫一個私有的init方法(重新實現(xiàn)初始化)
-(instancetype)initPrivate {
if (self = [super init]) {
}
return self;
}
// 3.單例實現(xiàn)方法(系統(tǒng)線程加鎖方式)
+(instancetype)sharedHandle {
static Datahandle *datahandle = nil;// 用static修飾,這個方法只走一次
@synchronized (self) {// 同步保護(hù)(互斥鎖,保證線程安全)
if (!datahandle) {
datahandle = [[Datahandle alloc]initPrivate];// 用重新寫的私有初始化
}
}
return datahandle;
}
// 方法二(傳統(tǒng)創(chuàng)建方式)
//+(instancetype)sharedHandle{
//
// static Datahandle *datahandle = nil;
//
// if (!datahandle){
//
// datahandle = [[Datahandle alloc] init];
// }
// return datahandle;
//}
// 方法三 (線程方式--最優(yōu))
//+(instancetype)sharedHandle {
//
// static Datahandle *datahandle = nil;
// static dispatch_once_t onceToken; //給單例加了一個線程鎖
//
// dispatch_once(&onceToken, ^{
//
// datahandle = [[Datahandle alloc] init];
// });
// return datahandle;
//}
@end




效果:



單例相關(guān)知識點
1.簡介
就是一個實例,單例是全局都可以使用的唯一的一個類,相當(dāng)于一個全局變量,它提供了對類的對象所提供的資源的全局訪問點。因此需要用一種只允許生成對象類的唯一實例的機制;
作用:可以保證的程序運行過程,一個類只有一個示例,而且該實例易于供外界訪問,從而方便地控制了實例個數(shù),并節(jié)約系統(tǒng)資源(就是不論在哪里需要用到這個類的實例變量,都可以通過單例方法來取得,而且一旦你創(chuàng)建了一個單例類,不論你在多少個界面中初始化調(diào)用了這個單例方法取得對象,它們所有的對象都是指向的同一塊內(nèi)存存儲空間(即單例類保證了該類的實力對象是唯一存在的一個))
2.單例實現(xiàn)思路
? 首先必須創(chuàng)建一個全局實例,通常存放在一個全局變量中,此全局變量設(shè)置為nil
? 提供工廠方法對該全局實例進(jìn)行訪問,檢查該變量是否為nil,如果nil就創(chuàng)建一個新的實例,最后返回全局實例
? 全局變量的初始化在第一次調(diào)用工廠方法時會在+allocWithZone:中進(jìn)行,所以需要重寫該方法,防止通過標(biāo)準(zhǔn)的alloc方式創(chuàng)建新的實例
? 為了防止通過copy方法得到新的實例,需要實現(xiàn)-copyWithZone方法
? 只需在此方法中返回本身對象即可,引用計數(shù)也不需要進(jìn)行改變,因為單例模式下的對象是不允許銷毀的,所以也就不用保留
? 因為全局實例不允許釋放,所以retain,release,autorelease方法均需重寫
注意:類只能有一個實例,并且必須從一個為人數(shù)值的訪問點對其訪問;這個唯一的實例只能通過子類化進(jìn)行拓展,并且拓展的對象不會破壞客戶端代碼

3.常見的系統(tǒng)單例
UIApplication(應(yīng)用程序?qū)嵗?
NSNotificationCenter(通知)
NSFileManager(文件管理):
NSUserDefaults(應(yīng)用程序設(shè)置):
UIScreen
NSApplication
NSFontManager
NSDocumentController
NSHelpManager
NSNull
NSProcessInfo
NSScriptExecutionContext
4.使用場景
單例模式應(yīng)用的場景一般發(fā)現(xiàn)在以下條件下:
1)資源共享的情況下,避免由于資源操作時導(dǎo)致的性能或損耗等。如上述中的日志文件,應(yīng)用配置。
2)控制資源的情況下,方便資源之間的互相通信。如線程池等。
簡單說就是:整個程序共用一份資源時(我們只需要對這份資源初始化一次)可以使用單例;例如:
1.設(shè)置單例類訪問應(yīng)用的配置信息
2.用戶的個人信息登陸后用nsuserdefaults 存儲,對登錄類進(jìn)一步采用單例封裝方便全局訪問
3.封裝一個單例對應(yīng)用多處對同一本地數(shù)據(jù)庫進(jìn)行操作
參考文章:http://blog.csdn.net/blueboyhi/article/details/51074372
