---------------------- Java培训、Android培训、iOS培训、.Net培训,期待与您交流! ---------------------
一、block
1.如何定义block变量block封装了一段代码,可以在任何时候执行。
block可以作为函数参数或函数的返回值,而其本身又可以带输入参数和返回值。
* block在程序运行时确定
block用来保存一端代码
block的标示:^
* block跟函数很像:
》可以保存代码
》有返回值
》有形参
》调用方式一样
int (^sumBlock)(int, int);
2.如何利用block封装代码
^(int a, int b){
return a+b;
};
// 如果block没有形参,^() 可以省略()
// 定义block变量
void (^myblock)() = ^{
NSLog(@"+++++++++++++++");
NSLog(@"---------------");
};
// 利用block变量调用block内部代码
myblock();
// 用一个block输出n条横线
void (^lineBlock)(int) = ^(int n){
for (int i=0; i<n; i++) {
NSLog(@"-------------");
}
};
lineBlock(4);
3.block访问外部变量
* block可以直接访问外部变量
* 默认情况下,block【不可以修改】外面的局部变量
* 给局部变量加上__block修饰,这个局部变量就可以在block中修改
__block int i = 10;
MyBlock printBlock = ^(int v1, int v2){
i++; // 可以修改局部变量了
NSLog(@"a=%d", i);
return v1+v2;
};
int f = printBlock(12, 13);
NSLog(@"%d", f);
4.利用typedef定义block类型
typedef int (^MyBlock)(int, int);
以后可以利用MyBlock这种类型定义block变量
MyBlock b1;
b1 = ^(int a, int b){
return 12;
}
// 指向函数的指针 定义为 SumP类型
typedef int (*SumP)(int, int);
// block 定义为 MyBock类型
typedef int (^MyBlock)(int, int);
SumP p = sum;
int c = p(10, 15);
NSLog(@"%d", c);
MyBlock sumBlock = ^(int a, int b){
return a+b;
};
int d = sumBlock(10, 15);
NSLog(@"%d", d);
MyBlock minusBlock = ^(int a, int b){
return a-b;
};
int e = minusBlock(10, 15);
NSLog(@"%d", e);
5. block与指向函数的指针
// block
int (^sumblock)(int, int) = ^(int a, int b){
return a+b;
};
int res = sumblock(10, 12);
NSLog(@"%d", res);
/********************************/
//指向函数的指针
int (*p)(int, int) = sum;
int c = p(10, 11);
NSLog(@"%d", c);
二、protocol
一系列方法的声明。
: 继承父类(OC单继承)
<> 遵守协议(协议多遵守)
() 分类
1. 协议的定义
@protocol 协议名称 <NSObject>
// 方法声明列表
@end
2. 如何遵守协议
1》类遵守协议
@interface 类名 : 父类名 <协议名称1, 协议名称2>
@end
2》协议遵守协议
@protocol 协议名称 <其他协议名称1, 其他协议名称2>
@end
一个协议遵守了另一个协议,就可以拥有另一个协议的所有方法声明。
3. 协议方法中声明的关键字
1》@required(默认)
要求实现。若不实现,则发出警告
2》@optional
不要求实现
只要一个类遵守了某个协议,就能拥有这份协议的所有方法声明。
NSObject是一个基类,同时也有个NSObject的基协议,基协议里有很多最基本的方法,比如:description、retain、release等。
建议每一个新的协议都遵守NSObject协议。
// 定义了一个名叫MyProtocol的协议
@protocol MyProtocol <NSObject>
// 默认@required
- (void)test4;
@required
- (void)test1;
- (void)test2;
@optional
+ (void)test3;
@end
4. 定义一个变量的时候,限制这个变量保存的对象遵守某个协议
类名<协议名称> *变量名;
id<协议名称> 变量名;
如果没有遵守对应的协议,编译器会警告(比较严重的)
// 要求obj2保存的对象必须是遵守MyProtocol这个协议
// Person 已经遵守了MyProtocol这个协议,没有警告
NSObject<MyProtocol> *obj2 = [[Person alloc] init];
obj2 = nil;
id<MyProtocol> obj3 = [[Person alloc] init];
obj3 = nil;
// 要求obj4,保存对象必须遵守MyProtocol3,并且继承Person
Person<MyProtocol3> *obj4 = [[Person alloc] init];
obj4 = nil;
5. @property中声明的属性也可以用来声明一个遵守协议的限制
@property (nonatomic, strong) 类名<协议名称> *变量名;
@property (nonatomic, strong) id<协议名称> 变量名;
6. 协议可以定义在单独.h文件中,也是定义在某个类的文件中
1》如果这个协议用在某个类中,应该把协议定义在这个类中
2》如果这个协议用在很多类中,就应该定义在单独.h文件中
7. 分类可以定义在单独.h和.m文件中,也是定义在原来类中
1》一般情况下,都是定义在单独文件中
2》也可以定义在原来类中,只要求能看懂语法
8. 声明某个字符串是一个协议
@protocol 协议名;
但是在实现文件.m中,还是要#import引入这个协议的.h文件。跟@class相同。
三、代理模式
请求方 —— 协议 —— 代理方
需要代理方具有协议里面的方法,才能实现请求方的代理需求。
设计原则:
》先让某个对象属性拥有代理权利
》清楚代理协议里的方法
》要保证能解耦
实现方法:
》先定义一个protocol,在其中声明一些和代理沟通的方法
》拥有一个代理属性 id<protocol> delegate;
》让代理类遵守这个协议protocol
(1)Person类的声明与实现
Person.h
#import <Foundation/Foundation.h>
@protocol TicketDelegate;
@interface Person : NSObject
// 拥有一个代理属性
// 代理类名随便,但必须遵守TicketDelegate协议
@property (nonatomic, strong) id<TicketDelegate> delegate;
- (void)wantMoive;
@end
Person.m
#import "Person.h"
#import "TicketDelegate.h"
@implementation Person
- (void)wantMoive
{
NSLog(@"xiang看电影");
// 叫代理去帮自己买票
double price = [_delegate ticketPrice];
int number = [_delegate leftTickets];
NSLog(@"通过代理,票价:%f,剩余票数:%d", price, number);
}
- (void)dealloc
{
NSLog(@"Person dealloced!!");
}
@end
(2)代理协议(谁遵守了这个协议,谁就可以做代理)
TicketDelegate.h
#import <Foundation/Foundation.h>
// 声明一些跑腿的方法
@protocol TicketDelegate <NSObject>
// 返回票价
- (double)ticketPrice;
// 剩余票数
- (int)leftTickets;
@end
(3)Agent类的声明与实现
Agent.h
#import <Foundation/Foundation.h>
#import "TicketDelegate.h"
@interface Agent : NSObject <TicketDelegate>
返回票价
//- (double)ticketPrice;
//
剩余票数
//- (int)leftTickets;
@end
Agent.m
#import "Agent.h"
@implementation Agent
- (double)ticketPrice
{
// ...查票价
return 1;
}
- (int)leftTickets
{
// ...查票数
return 1000;
}
@end
(4)运行代理
Person *p = [[Person alloc] init];
// 代理
Agent *a = [[Agent alloc] init];
// 设置人的代理
p.delegate = a;
// 人打算看电影
[p wantMoive];