------Java培训、Android培训、iOS培训、.Net培训 期待与您交流! -------
本篇的主题:block和protocol
block
Block封装了一段代码,可以在任何时候执行
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内部被修改
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的相关内容。