在异步编程时常需要进行函数回调,在C#中会用匿名委托或者lambda表达式讲一个操作作为参数进行传递.
ObjC中是使用对于闭包的实现,在块状中我们可以持有或引用局部变量. 同时利用Block可以将一个操作作为参数进行传递;
例:
int (^myBlcok)(int ,int)=^(int m,int n){
return m+n;
}; //无参数时大括号前()可省略
myBlock(10,5); //调用块,省略了接受块返回值;
总结:经过简单了解C与OC;发现从最小的一个变量到表达式到一个函数等,其实只有两点作用: 值(返回值) 与 功能(行为,方法,作用).
一行代码,按使用了值 或 功能来解读比较容易理解.
- 如果回调方法比较少,1~2,最好不要超过3个,这个时候使用block比较合适
- 如果回调方法太多,会让代码显得臃肿,反而不好维护
-如果回调方法非常多,同时又不用每一个方法都必须实现,这个时候用delegate会比较方便!
定义使用前加上声明.__weak typeof(obj) weakself = self;
类似函数指针,直接在定义格式之前加 typedef关键字,之后变量名就是类型的别名了.
typedef viod (^别名)(形参);
一般以后需要使用block作为函数方法的参数时,为方便最好用别名.而在作用返回值时,一定需要别名,因为编译器不能识别做此时类型做何种解释.
延伸:经过测试,block在编译时按代码顺序,而运行时按调用顺序(变量作用域)
根据block在内存中的位置
"NSGlobaBlock"类似函数,存于代码区--全局block
"NNStackBlock"栈区,函数返回后的Block--栈
"NSMallocBlock"堆block--堆
**面试题:**block的@property参数(内存管理参数)为什么要用copy:如果不用copy,此时不论ARC还是MRC都是栈Bolck,栈block会提前释放(}),导致无法继续使用;可以copy到堆区手动管理内存.(而字符串copy是防止字符串如果是非常量的,外部可变,造成非预估的结果;)
Block_copy将block及内部变量拷贝到堆区.
使用完毕用Blok_release(block变量)释放此堆区空间;
在ObjC中使用@protocol定义一组方法规范. 实现此协议的类 也必须实现对应的方法. 面向对象的语言接口本身是对象行为描述的 协议规范, 也就是说ObjC中@protocol和其他语言的接口定义是类似的, 只是ObjC的@interface关键字已经用于定义类了, 因此不会像C# 和Java中那样使用interface来定义接口;
只声明而不实现方法 ,遵守此协议的类要实现协议声明的特定方法; .h
(有@class声明类似)
@protocol 协议名 <系统协议>,<其他协议2>…
//方法声明列表
@end
类声明文件中:
@interface 类名:父类<协议1,协议2>
@end
只需在此类的.m文件中实现协议声明方法即可(有些必须实现,有些选择实现);
1. 做类型限制:程序员间交流
格式:
id<协议名>obj;//表明 如果要给obj赋值,则赋值的对象必须遵守"协议"才可以赋值.不满足会有警告;
即id<协议名> obj=[类1 new],必须类1要遵守此协议;id 可换成类名,记得加*;
引申的,在对象做实例变量时也可限制,例:@prperty Dog<协议> *dog
2.代理设计模式
使两个不同意义的事物分离解耦.
一种常见编程思想:有些事自己不好做,找代理做;传入的对象,代替当前类完成摸个功能;
原理:对象关联关系的类型限制(A对象拥有遵守特定协议的对象B)白手套作为主子的实例变量;
应用场合:
思路:
设置代理.
@interface 类名(分类名)
@implementation 类名
原类直接调用
注意:
1)分类不能扩展任何新的实例变量;
2)分类可以访问原类的成员变量;(相当于原类方法调用)
3)如果分类中存在和原类同名方法,优先使用分类(功能更新);
4)如果多个分类都有同名方法,调用最后一个参与编译的分类同名方法;在Compile Sources 文件编译可以看到顺序;
就是NSObject(和系统类框架)的类别(分类)即系统类的分类,增加了所有类的功能;类别接口中指定的方法可能会或者可能不会被框架类实际地实现,而是被子类重写.
延展是分类一个特例,匿名.且新添加的方法一样要予以实现
@interface MyClass () {
float value; //可以新增实例变量
}
-(void)setValue:(float)newValue;
@end
使用: