黑马程序员——OC语言基础篇---block和protocol

------Java培训、Android培训、iOS培训、.Net培训 期待与您交流! -------

本篇的主题:block和protocol

block

Block封装了一段代码,可以在任何时候执行
Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。
苹果官方建议尽量多用block。在多线程、异步任务、集合遍历、集合排序、动画转场用的很多
标志是^
>跟函数很像
>可以保存代码
>有返回值
>有形参
>调用方法一样

(1) 不带形参的block用法

#import <Foundation/Foundation.h>

int main()
{
    //不带形参的block定义
    void (^printBlock)() = ^{
        NSLog(@"这里是不带形参的block");
    };
    printBlock();
    return 0;
}
运行结果
2015-04-15 22:31:11.543 03-block[5180:303] 这里是不带形参的block
不带参数的用法比较简单,大家看一下就OK了,这里不再讲了。

(2) 带形参的block用法

在前面讲C语言的指针的时候,曾提到过,block的使用和指向函数的指针用法很类似,在这里,我们就把之前的代码用block来实现一下吧。
#import <Foundation/Foundation.h>
typedef int (^MyBlock)(int,int);

int main()
{
    int num1 = 20 , num2 = 13;
    MyBlock sumBlock = ^(int a,int b){
        return a + b;
    };
//    int (^sumBlock)(int,int) = ^(int a,int b){
//         return a + b;
//    };

    MyBlock minusBlock = ^(int a, int b){
        return a - b;
    };
    NSLog(@"\n和是%d\n差是%d",sumBlock(num1,num2),minusBlock(num1,num2));

    return 0;
}

被注释掉的代码就是不带参数block的定义方法,上述代码使用了typedef自定义了一个可以传入两个参数的block类型,简化代码
关于block的注意点
block内部可以访问外面的变量
默认情况下,block内部不能修改外面的局部变量的值
但是,给局部变量加上__block关键字,这个局部变量就可以在block内部被修改
这样上面的代码,其实可以不用传参数,也就是这样:
#import <Foundation/Foundation.h>
typedef int (^MyBlock)();

int main()
{
    __block int num1 = 20 , num2 = 13;
    MyBlock sumBlock = ^(){
        return num1 + num2;
    };

    MyBlock minusBlock = ^(){
        return num1 - num2;
    };
    NSLog(@"\n和是%d\n差是%d",sumBlock(num1,num2),minusBlock(num1,num2));

    return 0;
}

protocol

1. 基本用途

可以用来声明一大堆方法(不能声明成员变量)
只要某个类遵守了这个协议,就相当于拥有这个协议中的所有方法声明
只要父类遵守了某个协议,就相当于子类也遵守了这个协议

2. 格式

    协议的编写
@protocol 协议名称
// 方法声明列表
@end
  某个类遵守协议
@interface 类名 : 父类 <协议名称>
@end

3. 关键字

协议中有2个关键字可以控制方法是否要实现(默认是@required),在大多数情况下,用途在于程序员之间的交流
@required:这个方法必须要实现(若不实现,编译器会发出警告)
@optional:这个方法不一定要实现

4. 协议遵守协议

一个协议可以遵守其他多个协议,多个协议之间用逗号 , 隔开
一个协议遵守了其他协议,就相当于拥有了其他协议中的方法声明
@protocol 协议名称 <协议1, 协议2>
@end

5. 基协议

  NSObject是一个基类,最根本最基本的类,任何其他类最终都要继承它
其实还有一个协议,名字也叫NSObject,它是一个基协议,最根本最基本的协议
NSObject协议中声明很多最基本的方法,比如description、retain、release等
建议每个新的协议都要遵守NSObject协议

6. 定义变量时指定协议

// NSObject类型的对象,并且要遵守NSCopying协议
NSObject<NSCopying> *obj;
// 任何OC对象,并且要遵守NSCoding协议
id<NSCoding> obj2;

7.protocol的知识点小节

如何创建遵守某个协议的对象
NSObject<Myprotocol> *obj3 = [[Person alloc] init];
注意:要创建遵守某个协议的对象,必须用遵守了这个协议的类来创建

保存一个对象:遵守某个协议并且继承某个类
Person<Myprotocol> *p1 = [[Person alloc] init];
set方法遵守某个协议
@property (nonatomic,strong) id<Myprotocol> obj;

与@class类似的用法
不用在.h里import 协议文件,使用@protocol,真正用到的时候再import

协议的总结
1.协议的定义
@protocol Myprotocol <NSObject>
@end
2.遵守协议
@interface 类名 : 父类 <协议1,协议2>
@end
3.协议中方法声明的关键字
@required 默认
要求实现,如果没有实现会发出警告
@optional
不要求实现,怎样都不会有警告
4.定义一个变量的时候,限制这个变量保存的对象遵守某个协议
类名<协议名> *变量名;
id<协议名> 变量名;
如果没有遵守对应的协议,编译器会警告

5.@property中声明的属性也可以用作一个遵守协议的限制
@property (nonatomic,strong) 类名<协议名> *属性名;
@property (nonatomic,strong) id<协议名> 属性名;
@property (nonatomic,strong) id<Myprotocol> obj;

协议的位置只要写在.h文件里,可以随便写
协议写在类的里面:当这个协议只用在这个类的时候,就写在里面
写在外面(单独写一个头文件):该协议用在很多类中,应该单独写

协议一般用在代理模式和察者模式

协议的应用--代理模式

其实这用组合可以实现,但是耦合性太强,不利于程序的拓展性,这里通过协议来实现。
首先需要有两个类Person和Agent,Agent遵守TicketProxy这个协议。
TicketProxy协议
#import <Foundation/Foundation.h>

@protocol TicketProxy <NSObject>
- (int) AskTicketPrice;
- (int) LeftTicketsCount;
@end
Agent类
#import <Foundation/Foundation.h>
@protocol TicketProxy;<pre name="code" class="objc">@property (nonatomic,strong) id<TicketProxy> agent;

@interface Agent : NSObject <TicketProxy>;@end
 实现协议中的方法 
#import "Agent.h"
#import "TicketProxy.h"
@implementation Agent
- (int) AskTicketPrice
{
    return 100;
}
- (int) LeftTicketsCount
{
    return 200;
}
@end

Person类
#import <Foundation/Foundation.h>
@protocol TicketProxy;
@interface Person : NSObject
@property (nonatomic,strong) id<TicketProxy> agent;
- (void) wantToBuyTicket;
@end
注意
@property (nonatomic,strong) id<TicketProxy> agent;
这句并没有特别定义哪一个类,而是定义了一个遵守一个协议的对象,这样只要有遵守了这个协议的对象都可以是Person的代理,这也就表示,如果将来代理换掉了,我这里的代码并不用修改,程序的拓展性很好。
#import "Person.h"
#import "TicketProxy.h"
@implementation Person
- (void)wantToBuyTicket
{
    int price = [_agent AskTicketPrice];
    int count = [_agent LeftTicketsCount];
    NSLog(@"票价:%d,余票:%d",price,count);
}
@end
声明时只使用@protocol声明这是一个协议,在实现的时候再引入协议,这样有利于提高程序的性能
main.m
#import <Foundation/Foundation.h>
#import "Agent.h"
#import "TicketProxy.h"
#import "Person.h"
int main()
{
    Person *p =[[Person alloc] init];
    Agent<TicketProxy> *a = [[Agent alloc] init];
    p.agent = a;
    [p wantToBuyTicket];
    return 0;
}
运行结果:
2015-04-15 23:34:25.363 02-代理模式[5797:303] 票价:100,余票:200

代理模式(设计模式)在很多场合都有应用,重要的是它这种设计的思想

好了,OC的基础知识到这里也就告一段落了,接下来是一篇关于Foundation的相关内容。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值