一 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的數字加一
[objc] view plaincopy
- - (IBAction)up:(id)sender {
- NSInteger lastNum = self.label.text.integerValue;
- lastNum++;
- self.label.text = [NSString stringWithFormat:@"%ld",lastNum];
- }
Down Button使用方式二,用代碼添加
定義如下函數,來處理Down Button點擊事件
[objc] view plaincopy
- -(void)down:(id)sender{
- NSInteger lastNum = self.label.text.integerValue;
- lastNum--;
- self.label.text = [NSString stringWithFormat:@"%ld",lastNum];
- }
然後,在ViewDidLoad函數中,用代碼綁定target-action
[objc] view plaincopy
- [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定義)
[objc] view plaincopy
- <pre name="code" class="objc">
[objc] view plaincopy
- //
- // 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的接口裡定義
[objc] view plaincopy
- </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的事件中進行事件傳遞,
[objc] view plaincopy
- -(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的方法
[objc] view plaincopy
- <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中,看到監聽事件成功。
[objc] view plaincopy
- 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注冊監聽的屬性
[objc] view plaincopy
- [self.firstView addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew contextvoid*)&PrivateKVOContext];
然後,在如下方法中監聽變化,
[objc] view plaincopy
- -(void)observeValueForKeyPath:(NSString *)keyPath ofObjectid)object changeNSDictionary *)change contextvoidvoid *)context{
- if (context == &PrivateKVOContext){
- NSLog(@"first view backgroud color changed from KVO");
- NSLog(@"%@",change.description);
- }
- }
這裡的context
[objc] view plaincopy
- static const int PrivateKVOContext = 0;
7 Notification(盲通信,用處也比較廣泛)
在RandomChangeColorView的響應事件中,進行廣播
[objc] view plaincopy
- [[NSNotificationCenter defaultCenter] postNotificationName:KRANDOMCHANGECOLORVIEWNOTIFICATION object:randomColor];
然後,在ThridViewController中監聽廣播
[objc] view plaincopy
- [[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和通知都應該在合理的位置取消注冊
[objc] view plaincopy
- -(void)viewWillDisappear:(BOOL)animated{
- [self.firstView removeObserver:self forKeyPath:@"backgroundColor"];
- [[NSNotificationCenter defaultCenter] removeObserver:KRANDOMCHANGECOLORVIEWNOTIFICATION];
- }
點擊第三個ViewController的兩個View,在Log中看到了監聽成功
[objc] view plaincopy
- 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。
嵌入式Segue
自定義Segue
Modal Segue和Unwind Segue
三 最後說說代理和Notification的區別
代理就像打電話,只有先接通了才能進行信息交流。而Notification就像是廣播,你收聽不收聽,多少個人收聽跟我沒關系,反正我要廣播,但是注意,你跟廣播站注冊了你要收聽廣播,但是你不收聽了卻不提前告訴廣播站。下次廣播站發現有通知要給你,你卻不知道哪去了,你就要遭殃了(App 有可能會崩潰)。
最後,附上整個Demo的下載鏈接。
CSDN鏈接
http://download.csdn.net/detail/hello_hwc/8408187