block、Protocol

block的简单使用                                                                                   

block的作用:用来存一段代码,其标志是^,它和函数有点类似,可以保存代码,有返回值,有形参.

sample code:

void (^myBlock)() = ^(){
 
    NSLog(@"---------");
};

sample code2:

// 带参数的Block使用实例
int (^SumBlock)(int,int) = ^(int a, int b){
    return a + b;
};

main函数调用

  int s =  SumBlock(10,11);
  NSLog(@"%d",s);

利用block输出n条横线:

void (^LineBlock)(int) = ^(int n){
 
    for (int i = 0;i < n;i++){
        NSLog(@"---------------");
    }
};

主函数调用

LineBlock(3); // 输出3条横线

使用typedef定义block类型                                                                                

block和函数一样,可以用typedef来定义

比如还是一个加法和减法的block,如果不使用typedef的话

 

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


而如果用typedef来定义的话就是这样

typedef int (^MyBlock) (int,int);
 
MyBlock SumBlock = ^(int a,int b){
    return a - b;
};
MyBlock MinusBlcok = ^(int a,int b){
       return a - b;
    };


这样的好处是,如果再遇到带两个整形参数的block,就可以直接调用,而不需要再写一遍

使用block修改局部变量                                                                                          

block内部可以访问外面的变量‍‍

默认情况下,block内部不能修改外面的局部变量

给局部变量加上__block关键字,这个局部变量就可以在block内部修改‍‍‍

void SampleCode()
{
   __block int a = 10; // 加上__block关键字
   void (^myblock)();
       myblock =^{
       a = 20;        // 这时局部变量a就可以在block中修改了
       };
}


协议Protocol                                                                                          

协议是用来存放方法声明的,注意,只能放方法,不能放变量;只能放方法声明,不能放实现.

只要某个类遵守了这个协议,那么就意味着他拥有了这个协议中所有的方法声明

协议的用法:

类遵守协议

定义一个Animal.h的协议,再定义一个Person.h类,假设Person要实现这个协议

Animal.h

//定义一个协议
@protocol Animal <NSObject>

@required     //必须实现的方法
-(void)eat;

@optional     //可选实现的方法
-(void)run;
-(void)say;
-(void)sleep;

@end

Person.h

#import <Foundation/Foundation.h>
#import "Animal.h"

@interface Person : NSObject<Animal>

-(void)eat;

@end

Person.m

#import "Person.h"@implementation Person

-(void)eat{
    NSLog(@"eating...");
}

@end

Protocol注意点                                                                                         

  1. 一个协议可以扩展自另一个协议,例如上面AnimalDelegate就扩展自NSObject,如果需要扩展多个协议中间使用逗号分隔;

  2. 和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的,我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意OC是弱语法,即使不实现必选方法编译运行也不会报错);

  3. 协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔;

  4. 协议的实现只能在类的声明上(.h),不能放到类的实现上(Person.m中不能实现);

  5. 协议中的方法可以在类声明文件.h中声明,也可以不声明直接在.m中实现,如果只实现不声明则认为是私有方法;

  6. 协议中不能定义属性、成员变量等,只能定义方法;


协议遵守协议

格式如下:

@protocol 协议名称 <其他协议名称1, 其他协议名称2>

@protocol MyProtocol <MyProtocol1,MyProtocol2>

协议的提前声明

在类的声明文件中其实可以不用包含协议的.h文件,直接用关键字@protocol 协议名;就行了,而且可以连写多个,用逗号隔开

这样做会提升编译效率

#import <Foundation/Foundation.h>
// #import "Animal.h"
@protocol Animal;    // 这个就是告诉程序,Animal是个协议,可以代替上一句
@interface Person : NSObject<Animal>

-(void)eat;

@end


协议总结                                                                                                  

1.协议定义

@protocol Myprotocol <NSObject> // (这个NSObject是基协议)

// 方法声明...

end


2.如何遵守协议

    1>类遵守协议

    @interface 类名:父类名 <协议1,协议2>

       end

    2>协议遵守协议

    @protocol 协议名 <其他协议1,其他协议2>

      end

3.协议中方法声明的关键字

    1>@required(默认)

        必须实现,如不会发出警告

    2>@optional

        不要求实现,不会有警告

4.定义一个变量的时候,限制这个变量保存的对象遵守某个协议

类名<协议名> *变量名;

id<协议名> 变量名;

sample code:

NSObject <Myprotocol> *obj;

id <Myprotocol> obj2;

如不遵守对应的协议,编译器将会有一条长警告 

5.@property中声明的属性也可以用协议

@property (nonatomic,strong) 类名<协议名> *属性名

@property (nonatomic,strong) id<协议名> 属性名

sample code:

@property (nonatomic,strong) Dog<Myprotocol> *dog

@property (nonatomic,strong) id<Myprotocol> dog2

6.协议可以定义在协议文件中,也可以定义在当前类的头文件中

    1>如果这个协议只用在一个类中,那就定义在这个类当前的头文件中

   2>如果这个协议用在多个类中,那就单独定义在协议文件中

但协议还是建议尽量定义在单独的协议文件中

协议的代理设计模式                                                                                   

事实上在ObjC中协议的更多作用是用于约束一个类必须实现某些方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据和UI的分离,而且基本上所有的协议都是以Delegate结尾。


什么是代理模式呢?

我们不妨理解成,假设你家里需要打扫,但是你没时间,这时可以请一个保姆来帮你打扫卫生,这个保姆就是你的代理.

同样在OC中,一个对象想完成某件事,它可以把这事交给代理来完成.

假如一个人需要通过代理来买票

Person.h

/*
文件名:Person.h
项目名:Delegate
创建者:Hdbean
日  期:14-9-17
*/

#import <Foundation/Foundation.h>
#import "Agent.h"
#import "TicketDelegate.h"
@interface Person : NSObject
// 人要通过代理买票
- (void) buyTickets;
// 先给人设置一个代理的属性delegate
// 这里的id类型做了一个限制,就是必须遵守TicketDelegate这个协议的对象才可以使用delegate
@property (nonatomic,retain) id <TicketDelegate> delegate;
@end

Person.m

#import "Person.h"

@implementation Person
- (void)buyTickets
{
    //通过代理询问票价和余票,并将结果返回给price和tickets
    double price = [_delegate PriceOfTicket];
    int tickets = [_delegate SurplusTickets];
    NSLog(@"通过代理得知票价是%f,余票还有%d",price,tickets);
    
}
- (void)dealloc
{
    [_delegate release];
    [super dealloc];
}
@end

Agent.h

#import <Foundation/Foundation.h>
#import "TicketDelegate.h"
@interface Agent : NSObject <TicketDelegate>
// 这里代理的声明都放到了代理协议中去,只需要Agent遵守TicketDelegate协议即可
@end

Agent.m

#import "Agent.h"

@implementation Agent
// 票价
- (double)PriceOfTicket
{
    return 50;
}
// 余票
- (int)SurplusTickets
{
    return 100;
}

@end


TicketDelegate.h

#import <Foundation/Foundation.h>
// 因为这里原本是Agent.h中的声明,所以要包含他的头文件
#import "Agent.h"
@protocol TicketDelegate <NSObject>
// 代理需要做的事情,查询余票和票价
- (double) PriceOfTicket;
- (int) SurplusTickets;
@end

通过这个例子需要注意一下几点:

1.id可以表示任何一个ObjC对象类型,类型后面的”<协议名>“用于约束作为这个属性的对象必须实现该协议(注意:使用id定义的对象类型不需要加“*”)                                                          

2.在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件,这样可以提高编译效率

3.在编写代码中,协议代理文件通常以Delegate结尾,因为Delegate是代理的英文,这样做方便以后的管理和交接

4.代理协议文件中一定要包含基协议<NSObject>               

你可能感兴趣的:(block、Protocol)