152. block作为函数的参数--案例1。
5). 写1个类,数组类。将字符串数组的国家名字排序。
char *countries[] = {
"Nepal",
"China",
"Japan"
};
typedef BOOL (^NewType)(char *country1, char *country2);
@interface CZArray :NSObject
- (void)sortWithCountries:(char *[])countries andLength:(int)len;
- (void)sortWithCountries:(char *[])countries andLength:(int)len
andCompareBlock:(NewType)compareBlock;
@end
@implementation CZArray
- (void)sortWithCountries:(char *[])countries andLength:(int)len
{
for(int i=0; i<len-1; i++){
for(int j=0; j<len-1-i; j++) {
// 比较2个字符串的ascii码,让调用者自己确定比较规则。
// int res = strcmp(countries[j], countries[j+1]);
// BOOL (^compareBlock)(int)
// 比较j,j+1字符串的大小,并返回结果。
if(res > 0) {
char *temp = countries[j];
countries[j] = countries[j+1];
countries[j+1]=temp;
}
}
}
}
- (void)sortWithCountries:(char *[])countries andLength:(int)len
andCompareBlock:(NewType)compareBlock
{
for(int i=0; i<len-1; i++){
for(int j=0; j<len-1-i; j++) {
// 比较2个字符串的ascii码,让调用者自己确定比较规则。
// int res = strcmp(countries[j], countries[j+1]);
// BOOL (^compareBlock)(int)
// 比较j,j+1字符串的大小,并返回结果。
BOOL res = compareBlock(countries[j], countries[j+1]);
if(res == YES) {
char *temp = countries[j];
countries[j] = countries[j+1];
countries[j+1]=temp;
}
}
}
}
@end
CZArray *arr = [CZArray new];
// [arr sortWithCountries:countries andLength:sizeof(countries)/8];
[arr sortWithCountries:countries andLength:sizeof(countries)/8
andCompareBlock: ^BOOL(char *country1, char *country2) {
// 按国家名字排序。
int res = (int)strlen(country1) - (int)strlen(country1);
return res > 0;
}];
for(int i=0; i<sizeof(countries)/8; i++){
NSLog(@"%s", countries[i]);
}
/*[arr sortWithCountries:countries andLength:sizeof(countries)/8
andCompareBlock:^BOOL(char *country1, char *country2) {
// 比较字母顺序
int res = strcmp(country1, country2);
return res > 0;
}];*/
153. block作为函数的参数--案例2。
@interface CZArray {
int _arr[10];
}
- (void)bianLiWithBlock:(void (^)(int val))processBlock;
@end
@implementation CZArray
- (instancetype)init {
if(self = [self init]) {
for(int i=1; i<11; i++) {
_arr[i-1] = i*10;
}
}
return self;
}
/// 遍历数组中每个元素,然后根据自定义的block方法,做处理
- (void)bianLiWithBlock:(void (^)(int val))processBlock
{
for(int i=0; i<10; i++) {
// 调研这自己写1端代码,来处理遍历出来的元素。
// NSLog(@"%d", _arr[i]);
processBlock(_arr[i]);
}
}
@end
CZArray *arr = [CZArray new];
[arr bianLiWithBlock: ^(int val) {
NSLog(@"val = %d", val+1);
}];
154. block作为函数的返回值。
当将block作为返回值,返回值的类型,就必须是用typedef定义的短的类型。
typedef void (^NewType)();
NewType ttt() {
void (^block1)() = ^ {
NSLog(@"~~~~~~");
};
return block1;
}
NewType type = ttt();
type();
155. block与函数的异同。
- 函数与block的相同点: 都可以封装一段代码.
- 函数与block的不同点:
1). block是一个数据类型,函数是一个函数
2). 我们可以声明block类型的变量,函数就只是函数
3). block可以作为函数的参数.
156. 协议的基本使用
1. 协议: protocol.
作用:
- 专门用来声明一大堆方法(不能声明属性,也不能实现方法,只能用来写方法的声明).
- 只要某个类遵守了这个协议,就相当于拥有这个协议中的所有的方法声明.
2. 协议的声明
@protocol 协议名称 <NSObject>
方法的声明;
@end
新建一个协议的方式, NewFile->OC-File-protocol
协议的文件名:.h 并且只有一个.h文件
在协议中,只能用来声明方法
作用: 专门用来写方法声明的, 就是用来被类遵守的。
3. 类遵守协议
如果想让一个类拥有协议中定义的所有的方法声明,那么就让这个类遵守这个协议,
类只要遵守这个协议,那么这个类就拥有了这个协议中定义的所有的方法的声明了.
@interface 类名 : 父类名 <协议名称>
@end
:表示继承
<> 表示遵守的协议
当一个类,遵守了一个协议,那么就相当于这个类拥有了协议中定义的所有的方法的声明,
这个类只是拥有了这个协议中的声明而已,没有实现,所以,这个类,就应该实现协议中的方法.
如果类不实现协议中的方法,也不会报错,只是编译器会报警告,但是当创建对象,来调用 这个没有的实现的协议中的方法的时候就会报错.
类是单继承,但是协议可以多遵守
一个类值能有一个父类,但是一个类可以遵守多个协议
@interface 类名 : 父类名 <协议名称1, 协议名称2...>
@end
当1个类遵守了多个协议之后,就相当于这个类拥有了所有协议中定义的方法的声明,那么这个类,就应该实现所有协议中的方法.
但是仅仅只是有方法的声明,没有实现方法,要类自己去实现。
如果类不实现,编译器不会报错,只是给1个警告。
当我们创建对象,如果不调用这个协议方法,就不会报错。
如果要调用这个协议方法,就会报错。
157. 协议:@required 与 @optional 专门用来修饰协议中的方法。
5. @required 与 @optional
专门用来修饰协议中的方法。
关键作用:在于程序员沟通,告诉遵守协议的类 哪些方法是必须要实现的。
当1个类遵守了多个协议之后,就相当于这个类拥有了所有协议中定义的方法的声明.
在协议当中,如果方法的声明被
@required
修饰,那么这个协议的类就必须要实现这个方法,否则编译器会发出警告.
在协议当中,如果方法的声明被@optional
修饰,那么遵守这个协议的类可以实现这个方法,也可以不实现这个方法,不实现编译器也不会报警告.
无论@required与@optional都可以不实现,编译器不会报错,仍然可以编译运行,唯一的区别:当遵守协议的类不实现协议中的方法的时候,@required会给出一个警告,@optional警告都没有,默认是@required.
158. 协议的继承
6. 协议可以从另外一个类继承,也可以多继承.
协议可以继承另外一个协议,A协议继承B协议,那么A协议中不仅有自己的方法的声明,还有B协议中的方法的声明。如果有一个类遵守了A协议,那么这个类就拥有了A、B协议中所有方法的声明.
// 协议之间继承的语法格式:
@protocol A协议名称 <B协议名称>
@end
效果:
代表A协议继承自B协议,A协议中既有自己方法的声明,也有B协议中的方法声明。
NSObject:
写协议的规范:要求所有的协议直接或者间接的从NSObject基协议继承.
在Foundation框架中,有1个类,叫NSObject 是所有OC类的基类.
在Foundation框架中,有1个协议,叫做NSObject.
类和框架的名称可以一致。
NSObject协议被NSObject类遵守。所以,NSObject协议中所有的方法,全部的OC类都拥有了。
这么说,所有的OC类都遵守了NSObject协议。NSObject协议叫做基协议。
159. 协议的类型限制。
7. @protocol类型限制
1). 这个指针指向遵守了指定协议的任意对象,否则就会报警告
NSObject<协议名称> *指针名;
id<协议名称> *指针名;
NSObject<StudyProtocol> *obj = [Student new];
// 协议的类型限制,只能指向遵守了协议的对象.
NSObject<StudyProtocol> *obj =@"Tom";
// 报警告
2). 声明1个指针变量,要求这个指针变量指向的对象必须遵守多个协议
NSObject<协议名称1, 协议名称2> *指针名;
id<协议名称1, 协议名称2> *指针名;
NSObject<StudyProtocol, SBProtocol> *obj = [Student new];
id<StudyProtocol, SBProtocol> id = [Student new];
3). 定义1个指针,指向遵守了学习协议的学生对象.
Student<StudyProtocol> *stu = [ITStudent new];
// 也可以将Student的子类,赋值给stu指针。
id<StudyProtocol> id1= [Student new];
[id1 study];
4). 为什么?
a. 遵守了某个协议的类,就相当于这个类拥有了这个协议所定义的行为
b. 因为要调用对象中的协议方法,
只有类遵守了这个协议,该类才能有协议中的方法.
// SportProtocol.h
@protocol SportProtocol <NSObject>
@required
- (void)run;
@optional
- (void)sleep;
@end
// Dog.h
#import "MyProtocol.h"
@interface Dog: NSObject <MyProtocol>
@end
// 实现Dog类中的run,sleep方法。
Dog *dog = [Dog new];
[dog run];
[dog sleep];