ios消息的交互方式

注意這些都是界面回傳(即從第二個界面傳到第一個界面,從第一個界面傳到第二個界面的時候用第二個界面的屬性便可)
 
iOS消息的交互方式有4種,分別爲:通知,代理,block,kvo
如今咱們對這個4中方式分別作詳細的介紹
 
 
通知
 
//1通知的發送平臺(信息的發佈者)
 
   [[NSNotificationCenter defaultCenter] postNotificationName:@"enterTicket" object:nil userInfo:@{@"index":@"0"}];//userInfo:通知攜帶的內容詳情@{key:index   value:須要跳轉的位置}
 
 
//2通知到的接收平臺(信息的接收者)
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enterTicket:) name:@"enterTicket" object:nil];
 
//處理信息的方法
- (void)enterTicket:(NSNotification *)noti {

    // 獲取通知的詳情信息
    NSString *indexStr = [noti.userInfo objectForKey:@"index"];
    NSInteger index = [indexStr integerValue];
   
 
}
 
 
 
 
//最後把通知移除
 [[NSNotificationCenter defaultCenter] removeObserver:self];
 
 
 
 
代理(代理模式是ios中最經常使用的一種方式)
代理就像打電話,個人代理我不擁有(weak),我能夠適時(時候我定)告訴個人代理消息(實現代理方法,代理方法中有個人數據,代理方法中含有的參數就是個人數據),協議就像電話,要想通話必須有電話(籤協議)而後肯定接電話的人delegate = self,接到電話去幹活(實現帶來方法,若是我須要信息的話代理把信息返回給我,表示代理方法中有返回值)
 
 
(李文全的理解)
所謂代理就是代理者可以處理代理事件(對代理對對象進行處理,本身能夠是本身的代理)(例如小孩須要照顧,能夠設置一個代理(保姆)照顧,代理(保姆)實現代理的方法(照顧小孩),這個方法中傳入一個小孩的屬性,就能夠對小孩的全部的屬性進行處理)
 
 
block 就只一個代碼塊,這個代碼塊當作參數傳遞,代碼塊的執行時間就是這個代碼塊的最終執行時間
 
 
block 就像個人小弟,我擁有block的變量我實實在在的擁有它(Strong)(block變量的聲明),我能夠適時告訴他作揍人(block變量實現同是能夠向他傳遞揍誰即參數)啥時候揍是我說了算(啥時候實現變量block,走完人給我反饋結果)
 
 誰主動(就是能夠控制傳值的時間,即控制何時調用block變量,和用代理調用代理方法)調用這個方法(代理方法或者block方法,誰裏面就擁有block變量或者變量);消息的傳遞能夠是相互的(即有參數有返回值)
1 block的聲明
 // 聲明類型
  // sumBlockblock變量// 變量首字小寫
    int(^sunBlock)(int,int);
 
    // SumB是類型別名//類名首字大寫
    typedef int(^SumB) (int,int);
2 block的定義
 
  sunBlock = ^(int x , int y ){
        return x +y;
    };// sunBlock是變量
 
 
       SumB bock_1 = ^(int x , int y ){
        return x +y;
    };// bock_1是變量
3 block的調用
 
sunBlock(1,2);//sunBlock變量的實現
 
bock_1(1,2);//bock_1變量的實現
 
 
方法的差數就是代碼塊
調用方法就是傳遞參數(代碼塊)
在這個方法中把這個代碼塊傳遞給新的block代碼塊
實現這個新的block代碼塊
要想實現兩個對象數據的傳遞必須保證這兩個對象同時存在(由於調用的對象必須有即信息傳遞方,blcok實現的對象必須有信息的接收方,用信息接收方的屬性接收,故信息的接收方法是block代碼的實現方,)
 
注意 :block 只能從第二個視圖傳入第一個視圖中,不能從第一個視圖中傳入第二個視圖
         代理既能夠從第一個視圖傳入第二個視圖中,也能從第二個視圖傳入第一個視圖
 
block實現和調用在兩個類中,
實現 - 傳差數(代碼塊)-調用-實現代碼塊內的內容
當按完調用,後再走實現的代碼(即最後的才走實現)
走的是同一個視圖控制器
 
 
 
補充: 界面傳值和對象傳值是不同的(明天)
 
 
 
 
 
 
 
 

2、Protocol(協議)java

(一)簡介ios

1.Protocol:就一個用途,用來聲明一大堆的方法(不能聲明成員變量),不能寫實現。objective-c

2.只要某個類遵照了這個協議,就擁有了這個協議中的全部方法聲明。設計模式

3.只要父類遵照了某個協議,那麼子類也遵照。app

4.Protocol聲明的方法可讓任何類去實現,protocol就是協議。框架

5.OC不能繼承多個類(單繼承)可是可以遵照多個協議。繼承(:),遵照協議(< >)函數

6.基協議:<NSObject>是基協議,是最根本最基本的協議,其中聲明瞭不少最基本的方法。post

7.協議能夠遵照協議,一個協議遵照了另外一個協議,就能夠擁有另外一份協議中的方法聲明。測試

 

(二)基本使用ui

 
 
建立一個協議
 
遵照協議
 
 
 
完成協議中聲明的方法的實現
 
 
 
 
測試程序
 
 
 

1.協議的定義

@protocol 協議名稱 <NSObject>

//方法聲明列表

@end;

2.如何遵照協議

(1)類遵照協議

@protocol 類名:父類名 <協議名稱1,協議名稱2>

@end

(2)協議遵照協議

@protocol 協議名稱 <其餘協議名稱>

@end;

3.協議方法聲明中的關鍵字

(1)required (默認)要求實現,若沒有實現則警告但不報錯

(2)Optional 不要求實現

4.定義變量時遵照協議的限制

類名<協議名稱> *變量名    NSObject<.Myprotocol> *obj;

Id  <協議名稱>  變量名   id  <.Myprotocol> obj1;

 

5.Property中聲明的屬性也能夠作遵照協議的限制

@property (nonatomic ,strong ) 類名<協議名稱> *屬性名;

@property (nonatomic ,strong ) id<協議名稱>  屬性名;

 

6.補充知識:協議自己寫在.h頭文件中,但也能夠定義在任何地方。當這個協議只有這個類使用遵照時,通常把協議寫在這個類裏邊,當這個協議須要多個類去實現時,就寫在外邊單獨的文件中。

 
 
 
 
 
 
 
 
 
 
 
 
代理就是委託對象
 
 
objective -c 協議(protocol)
協議(protocol)是object - c 中一個很是重要的語言特性,從概念上講,很是相似於java中接口,一個協議其實就是一系列中有關聯的方法的集合(爲方便後面敘述,咱們把這個協議命名爲myProtocol)協議中的方法並非由協議自己去實現,相反而是由遵循這個協議的其餘類來實現,換句話說 協議myprotocol只是完成對協議函方法的聲明而並並無論這些新協議方法的具體實現
 
聲明一個協議的語法很是簡單
@protocol myProtocol <NSObject>
@requiered
-(void)protocolNameA:(NSString*)string;
@optional
-(void)protocolNameB:(NSString*)string;
@end
第一行是聲明這個協議的名字爲myProtocol.尖括號中的NSObject自己也是一個協議,其中定義了不少基本的協方法。好比performSelector,isKindOfClass ,respond to Selector conformsToProtocol ,retain release 等
協議接口分爲 required 和 optional 兩類 required 顧名思義是說遵照這個協議的那個類「必需要」實現的接口,而optional則是能夠實現也能夠不實現。協議接口的定義和普通的方法定義是同樣的
最後一行@end 表示協議定義結束。這個協議的定義一般是在.h文件中.。
 
定義一個類遵循這個協議
@interface myClass <myProtocol>
@intreface myClass :NSObject<myProtocol>
@intreface myClass : NSObject<myProtocol,NScoding>
上面分別是三種不一樣的狀況,編譯的時候編譯器會自動檢查myClass是否實現了myProtocol中的必要的(@requierd)接口。若是沒有實現則會發送一個警告信息,另外須要注意的是,若是有有繼承myClass的子類,這些子類也是會自動遵循myClass所遵循的協議的,並且也能夠重載這些接口
 
 
爲何須要協議?
蘋果的官方文檔指出三個緣由
To declare mothods that others are expected to implement
To declare the interface to an object while concrealing its class
To capture similarties among classes that are not hierarchicallu related
其實還有第四個很重要的緣由,那就是減小繼承類的複雜性。一個經典的例子就是 IOS UI框架裏面的UITableViewController類。假如沒有「協議」功能。用戶就必須選擇用繼承和重載接口的方法來實現複雜的UI控制以及其餘事件的處理——這就對基類的設計提出了更大的挑戰了。對於像這樣一個table view,一個很好的實現方法就是採用協議,由協議裏的接口來控制不一樣的數據源以及各類複雜的用戶操做。UIKit中設計了兩個很好的協議UITableViewDelegate,UITableViewDataSource來實現UITableViewController的控制。任何遵循這兩個協議的類均可以實現對UITableView的控制。

關於 id類型的運用:(不喜歡鑽牛角尖的朋友,能夠略過這一部分)

 
id 類型在iOS中是一個通用類型,有點相似C語言的void*類型。編譯器不能檢查到定義爲id類型的變量的實際類型,id類型的識別是發生在運行時階段。可是咱們能夠用 id<protocol_name> obj;這樣的語法形式在編譯階段就可讓編譯器知道obj只能夠發送protocol_name中的消息,若是所發送的消息不在protocol_name中,編譯器會給一個警告信息「Instance method 'xxxx:' not found......」。這種狀況多用於代理模式的實現,好比某一個類有一個delegate 的property:
 
id <myProtocol>delegate;
這樣,在編譯階段咱們就能夠知道用delegate所發送的消息是否是在它所遵循的myProtocol中的消息。好了, 到這裏筆者鑽起了牛角尖,我把id後面的 <myProtocol>刪掉,而後用delegate發送一個並不存在於myProtocol中的消息,結果編譯器仍是給了「Instance method 'xxxx:' not found......」的警告信息。更奇怪的是,當發送一個存在於myProtocol中的消息時,編譯器居然沒有這樣的警告信息。這兩個測試並不能說明以前的解釋是錯誤的,姑且認爲id<myProtocol> delegate這種寫法是爲了便於知道這個delegate遵循了myProtocol的協議吧.
 
 
 
 
 
 
委託(delegate)也叫代理是iOS開發中經常使用的設計模式。咱們藉助於protocol(參考博文: objective-c協議(protocol))能夠很方便的實現這種設計模式。
 

什麼是代理?

蘋果的官方文檔給了很清晰的解釋:

Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

意譯一下就是:代理是一種簡單而功能強大的設計模式,這種模式用於一個對象「表明」另一個對象和程序中其餘的對象進行交互。 主對象(這裏指的是delegating object)中維護一個代理(delegate)的引用而且在合適的時候向這個代理髮送消息。這個消息通知「代理」主對象即將處理或是已經處理完了某一個事件。這個代理能夠經過更新本身或是其它對象的UI界面或是其它狀態來響應主對象所發送過來的這個事件的消息。或是在某些狀況下能返回一個值來影響其它即將發生的事件該如何來處理。代理的主要價值是它可讓你容易的定製各類對象的行爲。注意這裏的代理是個名詞,它自己是一個對象,這個對象是專門表明被代理對象來和程序中其餘對象打交道的。

 

Cocoa中的代理

Cocoa Touch框架裏大量使用了代理這種設計模式,在每一個UI控件類裏面都聲明瞭一個類型爲id的delegate或是dataSource,查看Cocoa的頭文件能夠發現不少以下的屬性:

 

 

@property(nonatomic, assign)id<UIActionSheetDelegate> delegate;   // weak reference

一般格式爲@property(nonatomic, assign)id<protocol_name> delegate;  即這個代理要遵循某一個協議,也就是說只有遵循了這個協議的類對象才具有代理資格。這同時也要求了代理類必須在頭文件中聲明遵循這個protocol_name協議並實現其中的@required方法,@optional的方法是可選的。

 
以UIActionSheet爲例,咱們定義一個View,當點擊這個View中的某一個按鈕時觸發UIActionSheet, 當用戶對UIActionSheet完成了某一項操做,好比Destruct按鈕被按下,或是cancel按鈕被按下,UIActionSheet會發送消息給delegate,由delegate完成對用戶操做的響應,好比打印一個字符串到屏幕上。圖示說明以下:
 
 
首先,咱們建立一個基於tab的工程,在FirstViewController.h中添加代碼,使這個類遵循UIActionSheetDelegate協議:
  1. @interface FirstViewController : UIViewController <UIActionSheetDelegate> 
 
在View中添加一個按鈕用於觸發這個ActionSheet,而後編寫這個按鈕的響應代碼: 
- (IBAction)invokeActionSheet:(id)sender {
 
    UIActionSheet *actionSheet = [[UIActionSheet alloc]
                                  initWithTitle:@"Delegate Example"
                                  delegate:self // telling this class(ViewController) to implement UIActionSheetDelegate
                                  cancelButtonTitle:@"Cancel"
                                  destructiveButtonTitle:@"Destruct"
                                  otherButtonTitles:@"Button 1",@"Button 2",nil];
 
    [actionSheet showInView:self.tabBarController.view];
    [actionSheet release];
}
 
 
注意,上面有一個很重要的設置就是參數中有個delegate:self,這個設置就是指明瞭UIActionSheet的代理爲self, 也即FirstViewController
而後在FirstViewController.m中實現UIActionSheetDelegate中的方法:
 
#pragma mark --UIActionSheet delegate methods
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    switch (buttonIndex) {
        case 0:
            self.myTextFromActionSheet.text = @"Action Destructed!";
            break;
        case 1:
            self.myTextFromActionSheet.text = @"Action Button 1 Clicked!";
            break;
        case 2:
            self.myTextFromActionSheet.text = @"Action Button 2 Clicked!";
            break;
        case 3:
            self.myTextFromActionSheet.text = @"Cancel Button Clicked!";
            break;
        default:
            break;
    }
 
}
 

上面的幾步咱們完成了對Cocoa中UIActionSheet已有代理的運用。然而咱們不少時候須要本身編寫定製的代理,該如何實現呢?

 

自定義代理

咱們要作的是,建立一個view,自定義一個代理實現更新這個view中的字符串。上面咱們已經建立好了一個tab工程,借用裏面的second view。咱們拖一個按鈕到上面命名爲ChangeText,響應函數爲- (IBAction)changeText:(id)sender;點擊這個按鈕進入一個modal view 名爲ChangeTextView,咱們在ChangeTextView中輸入一個字符串並在退出這個view後把這個字符串更新到second view上面。如何實現modal view和second view之間的數據傳遞呢?那就是代理!誰的代理?ChangeTextView的代理!由於咱們直接在ChangeTextView中輸入數據,須要由代理把輸入的字符串反饋到second view上面去。

一、建立一個新的類ChangeTextViewController,並建立相應的xib文件。

 
二、在ChangeTextViewController.h中聲明一個協議ChangeTextViewDelegate:
@protocol ChangeTextViewDelegate <NSObject>
 
- (void) textEntered:(NSString*) text;
 
@end
和UIActionSheet相似,在ChangeTextViewController中咱們也須要添加一個代理的聲明:
@property (assign, nonatomic) id<ChangeTextViewDelegate> delegate;
三、咱們還須要在ChangeTextViewController.xib中添加一個按鈕save,當按下這個按鈕會返回到second view中,並更新字符串。對save按鈕的響應函數爲:
- (IBAction)saveButtonClicked:(id)sender {
    //Is anyone listening
    if([delegate respondsToSelector:@selector(textEntered:)])
    {
        //send the delegate function with the amount entered by the user
        [delegate textEntered:textEntered.text];
    }
 
    [self dismissModalViewControllerAnimated:YES];
}
[delegate textEntered:textEntered.text];這句代碼的含義就是ChangeTextViewController通知代理,textEntered這個事件發生了,對textEntered這個消息的實現,即如何響應這個textEntered的事件由代理來實現。在本例中,SecondViewController就是ChangeTextViewController對象的代理。因此,咱們要對SecondViewController作相應的設置使其知足代理的條件。首先,在SecondViewController.h中聲明遵循協議ChangeTextViewDelegate。而後編輯ChangeText按鈕的響應函數- (IBAction)changeText:(id)sender;
- (IBAction)changeText:(id)sender {
    ChangeTextViewController *CTViewController = [[ChangeTextViewController alloc] initWithNibName:@"ChangeTextViewController" bundle:nil];
    //Assign this class to the delegate of ChangeTextViewController,
    //remember to make thie ViewController confirm to protocol "ChangeTextViewDelegate"
    //which is delared in file ChangeTextViewController.h
    CTViewController.delegate = self;
    [self presentModalViewController:CTViewController animated:YES];
}
注意,CTViewController.delegate = self;這句實現了SecondViewController成爲ChangeTextViewController對象的代理
 
 
 
 
block (代碼塊)
 
 
 
//信息的發佈者
 
信息發佈者的類
 
1 Blcok 類型重命名(這個Block用Person代替,這個Block中傳入參數是個字符串,返回的參數是void)
typedef void(^PersonBlock)(NSString *name);
 
2在這個類中聲明這種Block類型的屬性
PersonBlock _block;
 
3這個類中聲明一個帶有Block類型參數的方法
- (void)getPersonName:(PersonBlock)block;
 
 
4上面方法的實現
- (void)getPersonName:(PersonBlock)block {

    _block = block;
}
 
//信息的接受者
 
初始化信息發佈者的類
 Person *per = [[Person alloc] init];
調用信息發佈者的類中帶有Block參數的方法
[per getPersonName:^(NSString *name) {
      
        NSLog(@"%@",name);
       
    }];
 
Block是什麼?蘋果推薦的類型,效率高,在運行中保存代碼。用來封裝和保存代碼,有點像函數Block能夠在任什麼時候候執行。
Block和函數的類似性:(1)能夠保存代碼(2)有返回值(3)有參數(4)調用方式同樣
 
    
 
 (二)基本的使用
(1)定義BLOCK變量
Int(^SumBlock)(int,int) ;//有參數,返回值類型爲int
Void (^MyBlock)()//無參數,返回值類型爲空
(2)利用block封裝代碼

(3)Block訪問外部變量

1)Block內部能夠訪問外部變量;

2)默認狀況下,Block內部不能修改外部的局部變量

3)給局部變量加上__block關鍵字,則這個局部變量能夠在block內部進行修改。

 

(4)利用typedef定義block類型(和指向函數的指針很像)

Typedef int(^MyBlock)(int ,int);

之後就能夠利用這種類型來定義block變量了。

MyBlock a,b;  

a=^(int a,int b){return a-b;};

MyBlock b2=^(int n1,int n2){return n1*n2;}
 
 
3..
 
 
 
 
 
//注意事項
 
根據程序加載順序
初始化
 
 
 
//——————————————————信息發佈者的類.h文件-------------------------------------
#import <Foundation/Foundation.h>
 
typedef void(^PersonBlock)(NSString *name);
@interface Person : NSObject
{

    PersonBlock _block;

}



- (void)getPersonName:(PersonBlock)block;



@end
 
 
//-------------------- 信息發佈者的類.m 文件——————————————————//
 
#import "Person.h"

@implementation Person
{

    NSString *_name;

}
- (id)init {

    if (self = [super init]) {
       
       
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            _name = @"曉彬";
           
            _block (_name);
           
        });
       
    }

    return self;
}



- (void)getPersonName:(PersonBlock)block {

    _block = block;

}


@end
 
//信息接受者文件
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
   
    Person *per = [[Person alloc] init];
   
    [per getPersonName:^(NSString *name) {
      
        NSLog(@"%@",name);
       
    }];
   
   
   
   
   
}
@end
 
 
 
 
kvo
  //直接修改屬性值,不能觸發KVO
    //    _happyValue--;
   
    //1.調用set方法來修改屬性值,能夠觸發KVO
    //    self.happyValue = _happyValue - 1;
   
    //2.使用KVC修改屬性值,也能觸發KVO
    NSInteger value = _happyValue;
    NSNumber *valueNumber = [NSNumber numberWithInteger:--value];
    [self setValue:valueNumber forKey:@"happyValue"];
   
    //修改hungryValue
    self.hugryValue = _hugryValue - 2;
 
 
 
_children = child;
       
        //使用KVO來監聽小孩屬性值的變化
        //_children 做爲被觀察者
        //observer 事件的觀察者:self
        //KeyPath:監聽被觀察者的某個屬性值
        //options:
        //NSKeyValueObservingOptionNew:監聽觀察修改後的屬性值
        //NSKeyValueObservingOptionOld:監聽觀察修改前的屬性值
        [_children addObserver:self
                    forKeyPath:@"happyValue"
                       options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
                       context:nil];
       
   
/
 
 block 是匿名的代碼端
 
// 聲明和實現
(^block名  )(參數){
 代碼段
}
 
 
 
 
// 調用
block 變量
/
相關文章
相關標籤/搜索