【Objective-C 基础】4.分类和协议

 

1.分类

OC提供了一种与众不同的方式--Category,可以动态的为已经存在的类添加新的行为(方法)

这样可以保证类的原始设计规模较小,功能增加时再逐步扩展。

使用Category对类进行扩展时,不需要创建子类

Category使用简单的方式,实现了类的相关方法的模块化,把不同的类方法分配到不同的分类文件中

()代表着一个分类 ()中的代表者分类的名称

也可以为系统子类的类添加一些扩展方法

2.协议(Protocol)

1.简单来说就是一系列方法的列表,其中声明的方法可以被任何类实现。这种模式一般称之为代理(delegation)模式。

2.模拟实现Button的点击监听机制

a.声明代理

#import <Foundation/Foundation.h>
@class  Button;
//<>代表实现某个协议
@protocol ButtonDelegate <NSObject>
-(void)onClick:(Button *)btn;
@end

@interface Button : NSObject
@property (nonatomic,retain) id<ButtonDelegate> delegate;
-(void)click;
@end
#import "Button.h"


@implementation Button

-(void)dealloc{
    //释放Button 同时释放delegate
    [_delegate release];
    [super dealloc];
}
-(void)click{
    //判断监听器是否有OnClick:方法
    if([_delegate respondsToSelector:@selector(onClick:)]){
        [_delegate onClick:self];
    }else{
        NSLog(@"监听器没有实现onClick方法");
    }
}
@end

b.定义一个类ButtonListener遵循ButtonDelegate协议

#import <Foundation/Foundation.h>

//对协议进行提前声明 ,跟@class的用途是一样的
@protocol ButtonDelegate;

@interface ButtonListener : NSObject <ButtonDelegate>

@end
#import "ButtonListener.h"
#import "Button.h"
@implementation ButtonListener

-(void)onClick:(Button *)btn{
    NSLog(@"ButtonListener已经监听到按钮%@被点击",btn);
}
@end

c.调用

#import <Foundation/Foundation.h>
#import "Button.h"
#import "ButtonListener.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
     
        Button *button=[[[Button alloc] init]autorelease];
        Button *button2=[[[Button alloc] init]autorelease];
        ButtonListener *listener=[[[ButtonListener alloc] init]autorelease];
        button.delegate=listener;
        button2.delegate=listener;
        //按钮1被点击
        [button click];
        [button2 click];
    }
    return 0;
}

打印结果:

2013-08-29 22:00:24.276 Protocol[6473:303] ButtonListener已经见听到按钮<Button: 0x1001098d0>被点击

2013-08-29 22:00:24.281 Protocol[6473:303] ButtonListener已经见听到按钮<Button: 0x10010b690>被点击

3.Protocol补充

#import <Foundation/Foundation.h>

@protocol Study <NSObject>
//不加限制 默认是required 
//@required   表示必须实现的方法
//虽然是必须实现,但编译器并不强求某个类必须实现
@required
-(void)test;
-(void)test1;
//@optional 表示可选(可实现、也可以不实现)
@optional
-(void)test2;
@end
#import <Foundation/Foundation.h>
#import "Study.h"
#import "Learn.h"
@protocol Study,Learn;
//遵循多个协议
@interface Student : NSObject <Study,Learn>

@end
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Student *stu=[[[Student alloc ]init]autorelease];
        //
        if([stu conformsToProtocol:@protocol(Study)]){
            NSLog(@"Student遵守了Study这个协议");
        }
    }
    return 0;
}

2013-09-02 21:44:08.659 Protocol[3491:303] Student遵守了Study这个协议

3.Block

1.Block封装了一段代码,可以在任何时候执行。

a.Block定义和调用

        //Block定义
        int (^Add) (int,int)=^(int a,int b){
            return a+b;
        };
        //调用Block
        int a=Add(5,6);
        NSLog(@"a=%i",a);//打印结果a=11;

b.使用typedef定义

typedef int (^Add) (int,int);
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Add add=^(int a,int b){
            return a+b;
        };
        NSLog(@"123+321=%i",add(123,321));//打印结果
    }
    return 0;
}

c.Block可以访问外面定义的局部变量,但是不能修改。声明变量使用__block关键字可以进行修改。

        int i=10;
        int j=11;
        __block int k=12;
        Add add=^(int a,int b){
            NSLog(@"i=%i",i);
            //j=111;//variable is not assignable
            k=122;
            NSLog(@"k=%i",k);
            return a+b;
        };

d.使用block实现回调

#import <Foundation/Foundation.h>
@class  Button;
//<>代表实现某个协议
typedef void (^ButtonBlock) (Button *);

@interface Button : NSObject
@property (nonatomic,assign) ButtonBlock block;
-(void)click;
@end
#import "Button.h"


@implementation Button

-(void)click{
    _block(self);
}
@end
#import <Foundation/Foundation.h>
#import "Button.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Button *btn=[[[Button alloc] init]autorelease];
        btn.block=^(Button *btn){
            NSLog(@"按钮%@被点击了",btn);
        };
        [btn click];//打印:按钮<Button: 0x1001098d0>被点击了
    }
    return 0;
}

 

2.Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似但是有区别。block是inline(内联函数)的,并且默认情况下它对局部变量是只读的。

3.苹果官方建议尽量多用block。在多线程、异步任务、集合遍历、集合排序、动画转场用的很多。

http://blog.csdn.net/totogo2010/article/details/7839061

 

posted @ 2013-08-22 23:26  Carve_Time  阅读(240)  评论(0编辑  收藏  举报