IOS中訊息傳遞的8種方式
原創Blog,轉載請註明出處
一 MVC簡介
MVC是將應用中的類組織起來的一種策略。是IOS開發最常用的設計模式,當然,還有諸如MVVM,VIPER等模式,不過不在本文的討論範疇。
MVC代表什麼:Model-View-Controller。
Model:應用是什麼(what the app is )
Controller:如何呈現Model
View:你看到的東西
注意:
1.Controller可以直接訪問Model和View。
2.Model和View不要直接通訊。
3.View和Model是不依賴於Controller的,這是最基本的,不然你的工程在測試和維護起來都非常麻煩。
二 訊息傳遞的8種方式
為了更好的理解訊息傳遞,我寫了個簡單的demo,三個ViewController分別展示不同的訊息傳遞方式。
第一個ViewController如圖
Up,Down兩個Button點選後分別會將Label的數字加減一
1 Outlet(Controller訪問View)
注意:Outlet應當是weak的,因為強Outlet不應該參與引用計數。
使用Outlet非常簡單,
在storyboard上拖出一個控制元件,然後control+drag拖出一個outlet,如圖沿著紅線拖拽
不要忘記給ViewController設定為自定義的類,不然開啟輔助編輯介面不會無法拖拽。
這樣,就可以用屬性的訪問方式來直接訪問label
2 target Action(盲通訊,View反饋給Controller)
Up Button使用方式一,在storyboard上拖拽
然後在自動建立方法種進行如下定義,這個方法負責將label的數字加一
- (IBAction)up:(id)sender {
NSInteger lastNum = self.label.text.integerValue;
lastNum++;
self.label.text = [NSString stringWithFormat:@"%ld",lastNum];
}
Down Button使用方式二,用程式碼新增
定義如下函式,來處理Down Button點選事件
-(void)down:(id)sender{
NSInteger lastNum = self.label.text.integerValue;
lastNum--;
self.label.text = [NSString stringWithFormat:@"%ld",lastNum];
}
然後,在ViewDidLoad函式中,用程式碼繫結target-action
[self.downButton addTarget:self action:@selector(down:) forControlEvents:UIControlEventTouchUpInside];
第二個ViewController很簡單,就是在Storyboard上拖出一個View,並把類選擇為我自定義的一個類CustomAnimateView,這個類裡實現了用代理,block,DataSource。
點選Animate按鈕,紅色的原點會移動到SecondViewController提供位置,移動的時間由DataSource提供,移動開始和結束的事件由Delegate來提供,移動結束的事件同時也由Block提供。
3 Delegate (View傳遞事件給Controller,也用用來Controller傳遞資料,用處比較廣泛,解耦合)
4 DataSource (View的資料來源,解耦合的方式)
5 Block(常常用來傳遞事件)首先定義Protocol和DataSource,以及響應完成的Block型別(typedef定義)
<pre name="code" class="objc">
//
// CustomAnimationView.h
#import <UIKit/UIKit.h>
@class CustomAnimationView;
typedef void(^AnimationFinishedBlock)();
@protocol CustomAnimationViewDataSource <NSObject>
-(NSTimeInterval)animationDuration;
-(CGPoint)AnimateToPoint;
@end
@protocol CustomAnimationViewDelegate <NSObject>
@optional
-(void)willStartAnimate:(CustomAnimationView *)view;
-(void)didFinishedAnimate:(CustomAnimationView *)view;
@end
然後,在CustomAnimationView的接口裡定義
</pre><pre name="code" class="objc"><pre name="code" class="objc">@interface CustomAnimationView : UIView
@property (weak,nonatomic) id<CustomAnimationViewDataSource>datasource;
@property (weak,nonatomic) id<CustomAnimationViewDelegate>delegate;
@property (copy,nonatomic) AnimationFinishedBlock completeBlock;
@end
最後,Button的事件中進行事件傳遞,
-(void)animate:(id)sender{
if (self.datasource == nil || CGPointEqualToPoint(self.circleView.center, [self.datasource AnimateToPoint])){
return;
}
if ([self.delegate respondsToSelector:@selector(willStartAnimate:)]) {
[self.delegate willStartAnimate:self];
}
[UIView animateWithDuration:[self.datasource animationDuration]
animations:^{
self.circleView.center = [self.datasource AnimateToPoint];
}
completion:^(BOOL finished) {
if ([self.delegate respondsToSelector:@selector(didFinishedAnimate:)]) {
[self.delegate didFinishedAnimate:self];
}
if (self.completeBlock) {
self.completeBlock();
}
}];
}
然後在SecondViewController中,讓SecondViewController遵循Delegate和DataSource,提供DataSource所需的必要方法,提供Delegate的方法
<pre name="code" class="objc">@interface SecondViewController ()<CustomAnimationViewDataSource,CustomAnimationViewDelegate>
@property (weak, nonatomic) IBOutlet CustomAnimationView *customview;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.customview.delegate = self;
self.customview.datasource = self;
self.customview.completeBlock = ^(){
NSLog(@"Got finished action from block");
};
}
// Do any additional setup after loading the view.
-(NSTimeInterval)animationDuration{
return 1.0;
}
-(CGPoint)AnimateToPoint{
return CGPointMake(200, 400);
}
-(void)willStartAnimate:(CustomAnimationView *)view{
NSLog(@"will start");
}
-(void)didFinishedAnimate:(CustomAnimationView *)view{
NSLog(@"did finished");
}
這樣,點選的時候,就會按照DataSource提供的動畫時間和動畫的結束點來執行,並且可以在Log中,看到監聽事件成功。
2015-01-29 20:29:06.582 MessageTransitionExample[3355:117440] will start
2015-01-29 20:29:07.584 MessageTransitionExample[3355:117440] did finished
2015-01-29 20:29:07.585 MessageTransitionExample[3355:117440] Got finished action from block
第三個ViewController如圖,兩個View(自定義的RandomChangeColorView)各添加了點選的手勢,點選的時候,隨機更改自己的backgroundColor,然後,第一個View由KVO的方式監聽變化,第二個View用Notificaition的方式來監聽變化
6 KVO(Model反饋給View)
在ThridViewController註冊監聽的屬性
[self.firstView addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew context:(void*)&PrivateKVOContext];
然後,在如下方法中監聽變化,
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if (context == &PrivateKVOContext){
NSLog(@"first view backgroud color changed from KVO");
NSLog(@"%@",change.description);
}
}
這裡的context
static const int PrivateKVOContext = 0;
7 Notification(盲通訊,用處也比較廣泛)
在RandomChangeColorView的響應事件中,進行廣播
[[NSNotificationCenter defaultCenter] postNotificationName:KRANDOMCHANGECOLORVIEWNOTIFICATION object:randomColor];
然後,在ThridViewController中監聽廣播
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorChange:) name:KRANDOMCHANGECOLORVIEWNOTIFICATION object:nil];<pre name="code" class="objc">-(void)colorChange:(NSNotification *)notificaiton{
NSLog(@"Color chagne from notification");
NSLog(@"%@",notificaiton.object);
}
這裡的KRNADOMCHANGECOLORNOTIFICATION是一個巨集定義的NSString
注意,註冊KVO和通知都應該在合理的位置取消註冊
-(void)viewWillDisappear:(BOOL)animated{
[self.firstView removeObserver:self forKeyPath:@"backgroundColor"];
[[NSNotificationCenter defaultCenter] removeObserver:KRANDOMCHANGECOLORVIEWNOTIFICATION];
}
點選第三個ViewController的兩個View,在Log中看到了監聽成功
2015-01-29 20:31:07.675 MessageTransitionExample[3355:117440] first view backgroud color changed from KVO
2015-01-29 20:31:07.676 MessageTransitionExample[3355:117440] {
kind = 1;
new = "UIDeviceRGBColorSpace 0.00784314 0.247059 0.168627 1";
}
2015-01-29 20:31:10.731 MessageTransitionExample[3355:117440] Color chagne from notification
2015-01-29 20:31:10.731 MessageTransitionExample[3355:117440] UIDeviceRGBColorSpace 0.388235 0.482353 0.835294 1
8 Segue在ViewController切換的時候,常常用來傳遞資訊
之前的幾篇文章,我詳細介紹了各種,segue,並且附上了demo。
Modal Segue和Unwind Segue三 最後說說代理和Notification的區別
代理就像打電話,只有先接通了才能進行資訊交流。而Notification就像是廣播,你收聽不收聽,多少個人收聽跟我沒關係,反正我要廣播,但是注意,你跟廣播站註冊了你要收聽廣播,但是你不收聽了卻不提前告訴廣播站。下次廣播站發現有通知要給你,你卻不知道哪去了,你就要遭殃了(App 有可能會崩潰)。
最後,附上整個Demo的下載連結。
CSDN連結