1. 程式人生 > >IOS中訊息傳遞的8種方式

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連結