iOS 代理和block的理解
首先两者作用是一样的,都是进行单一回调。不通的是,delegate是个对象,然后用过一个对象自己调用代理协议函数来完成整个流程。block是传递一个函数指针,利用函数指针执行来进行回调。还有在内存管理上需要注意,delegate不需要保存引用。block对引用数据有copy的处理。
1.block类型-存储代码块的类型
在异步编程时常需要进行函数回调,在C#中会用匿名委托或者lambda表达式讲一个操作作为参数进行传递.ObjC中是使用对于闭包的实现,在块状中我们可以持有或引用局部变量. 同时利用Block可以将一个操作作为参数进行传递;
blcok用法:
- 定义:返回值类型 ( ^变量名 ) ( 形参类型 );
- 赋值:变量名=^(形参){
代码块+形参变量
}; - 使用:变量(实参);
例:
int (^myBlcok)(int ,int)=^(int m,int n){return m+n;}; //无参数时大括号前()可省略myBlock(10,5); //调用块,省略了接受块返回值;
总结:经过简单了解C与OC;发现从最小的一个变量到表达式再到一个函数,其实只起两点作用: 值(返回值) 与 功能(行为,方法,作用).所以说一行代码,按它是使用了值 还是 功能来解读比较容易理解.
Block做使用场景:
- 如果回调方法比较少,1~2,最好不要超过3个,这个时候使用block比较合适
- 如果回调方法非常多,同时又不用每一个方法都必须实现,这个时候用delegate会比较方便!
block传值的循环引用问题:
只有当block直接或间接的被self持有时,在block使用self时才需要替换为weak self。如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。
__weak __typeof__(self) weakSelf = self;dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{__strong __typeof(self) strongSelf = weakSelf;[strongSelf doSomething];[strongSelf doOtherThing];});
typedef block格式
类似函数指针,直接在定义格式之前加 typedef关键字,之后变量名就是类型的别名了.typedef viod (^别名)(形参);
一般以后需要使用block作为函数方法的参数时,为方便最好用别名.而在block作用返回值时,一定需要别名,因为编译器不能识别做此时类型做何种解释.延伸:经过测试,block在编译时按代码顺序,而运行时按调用顺序(变量作用域)使用例子:KCButton.h
#import <Foundation/Foundation.h>
@class KCButton;
typedef void(^KCButtonClick)(KCButton *);@interface KCButton : NSObject#pragma mark - 属性
@property (nonatomic,copy) KCButtonClick onClick;#pragma mark 点击方法
-(void)click;
@end
KCButton.m
#import "KCButton.h"@implementation KCButton-(void)click{NSLog(@"Invoke KCButton's click method.");if (_onClick) {_onClick(self);}
}@end
main.m
KCButton *button=[[KCButton alloc]init];button.onClick=^(KCButton *btn){
NSLog(@"Invoke onClick method.The button is:%@.",btn);
};[button click];/*结果:Invoke KCButton's click method.Invoke onClick method.The button is:<KCButton: 0x1006011f0>.*/
block访问外部变量
- block内部可以访问外部局部变量,但是此时是const copy方式,地址不同,相当于值传递,只读的.如果外部定义时加前缀__block时,内部可改变外部局变值.
- block内部如果创建了和外部同名的变量,会屏蔽外部作用域.此时内部的变量也存在栈区;
原因:block本质是代码块,ARC下创建的时候在堆区,此时代码只是单纯储存,没有功能;当调用的时候,相当于代码增加到main中,这样代码块中创建的变量就跟正常的一样; (block调用完成内部变量即释放,而堆区的只在释放block时一起释放). - 如果是静态变量(static修饰局变,生命周期延长,存储在数据区(同初始化的全局))和全局变量.地址传递.此时block存储在全局区.
- 常量字符串@"abc",加__block会引用常量变量(如:a变量,a = @"abc",内部可以任意修改a 指向的内容)的地址。不加block就是@"abc"本身地址,不可变;
三种类型block
根据block在内存中的位置
"NSGlobaBlock"类似函数,存于代码区--全局block
"NNStackBlock"栈区,函数返回后的Block--栈
"NSMallocBlock"堆block--堆
- block内没有使用外部变量或是只使用了全局/静态变量时.存于全局代码区,为全局block;---(ARC和MRC下一致)
- 当使用外部变量时
- MRC下,block代码存于栈区;如果此外部变量A存于栈区,那么A会被copy到block分配的栈区;如果A是存于堆区,那么A在block块内与快外相同.
- ARC下,block代码存于堆区.如果此外部变量A存于栈区,那么A会被copy到block分配的堆区;如果A是存于堆区,那么A在block块内与快外相同.
- 如果需要修改外部变量,需要在变量前面声明__Block;
当使用下划线Block修饰外部变量时:- MRC下,无论变量A存于栈还是堆区,A在block块内与快外相同;
- ARC下,如果此外部变量A存于栈区,那么A会被转移而不是复制到堆区;如果A是存于堆区,那么A在block块内与快外相同.
面试题:block的@property参数(内存管理参数)为什么要用copy:如果不用copy,此时不论ARC还是MRC都是栈Bolck,栈block会提前释放,导致无法继续使用;可以copy到堆区手动管理内存.(而字符串copy是防止字符串如果是非常量的,外部可变,造成非预估的结果;)
block在MRC下得内存隐患(NNStacKBlock)
Block_copy将block及内部变量拷贝到堆区.使用完毕用Blok_release(block变量)释放此堆区空间;
block使用技巧
- block结构快速显示:inlineBlock...(也可右下角自定义快速显示其他格式)
- Block作为方法参数时,最好把参数列表部分加上,这样后面调用方法时,会自动有格式;
- 做方法参数时,需要加上返回值类型;
- 做返回值时,先定义别名,最后别忘记执行返回值;
- 方法中,void(^)()表示block类型同int,做参和返回值;做实例变量
@property (nonatomic, copy) void(^变量名)() - get点语法获取block类型实例变量时,自动执行,后面需加();
2.protocl协议的概念及使用
在ObjC中使用@protocol定义一组方法规范. 实现此协议的类 也必须实现对应的方法. 面向对象的语言接口本身是对象行为描述的 协议规范, 也就是说ObjC中@protocol和其他语言的接口定义是类似的, 只是ObjC的@interface关键字已经用于定义类了, 因此不会像C# 和Java中那样使用interface来定义接口;
1.定义:
只声明而不实现方法 ,而让遵守此协议的类实现协议声明的方法;在.h 中
@protocol 协议名 <系统协议>,<其他协议2>... //方法声明列表 @end
2.类遵守协议:
类声明文件中:
@interface 类名:父类<协议1,协议2>
@end
3.实现协议:
只需在此类的.m文件中实现协议声明方法即可(根据协议定义时@option的关键字,有些必须实现,有些选择实现);
4.应用:
- 协议只声明多个方法,不实现, 不能定义属性;
- 只要遵守协议,就可以拥有协议的所有方法声明;
- 一个类遵守协议而实现的方法,声明和实现都会遗传给子类,而没有实现的方法声明会遗传给子类,即协议可以 继承 ;
- 协议和类可以多对多,而一个协议又可以继承其他一个或多个协议.
- 所有协议默认遵守NSObject的基协议,其中声明了很多基本方法.
- 协议中有两个关键字:@required(默认)必须实现的.
- @optional 选择实现;作用域类似@public等关键字作用域
两大作用
1. 做类型限制:程序员间交流
格式:
id<协议名>obj;//表明 如果要给obj赋值,则赋值的对象必须遵守"协议"才可以赋值.不满足会有警告;
即id<协议名> obj=[类1 new],必须类1要遵守此协议;id 可换成类名,记得加*;
引申的,在对象做实例变量时也可限制,例:@prperty Dog<协议> *dog
2.代理设计模式使两个不同意义的事物分离解耦.一种常见编程思想:有些事自己不好做,找代理做;传入的对象,代替当前类完成摸个功能;原理:对象关联关系的类型限制(A对象拥有遵守特定协议的对象B)白手套作为主子的实例变量;应用场合:
- 当A发生了一些行为(ˇˍˇ) 想~告诉B或B想监听对象A的一些行为
- A无法处理某些行为的时候,让B帮忙;
思路:
- 先定义一个协议.
- 定义代理类,遵守此协议.
- 主类定义限定此协议类型的属性.
- 主类中要有行为 来触发代理.
设置代理.
用父类还是id<协议>
- 不使用父类的原因:
- 如果抽象一个父类的话, 还是有局限性, 因为很多时候, 不同类是无法抽象出共同的父类
的. , 不能多继承
3.Category
- 作用:在不修改原类的情况下扩展其他功能
- 目的:对类方法进行归类,便于分模块开发大型类,团队协作.
声明:@interface 类名(分类名)
实现:@implementation 类名
使用原类直接调用
注意:1)分类不能扩展任何新的实例变量;
- 2)分类可以访问原类的成员变量;(相当于原类方法调用)
- 3)如果分类中存在和原类同名方法,优先使用分类(功能更新);
- 4)如果多个分类都有同名方法,调用最后一个参与编译的分类同名方法;在Compile Sources 文件编译可以看到的的顺序;
分类的非正式协议:(面试题)
就是NSObject(和系统类框架)的类别(分类)即系统类的分类,增加了所有类的功能;类别接口中指定的方法可能会或者可能不会被框架类实际地实现,而是被子类重写.
分类的延展(匿名分类)Extendsion
延展是分类一个特例,匿名.且新添加的方法一样要予以实现
@interface MyClass () {float value; //可以新增实例变量}
-(void)setValue:(float)newValue;
@end
使用:
- 可以在原类.h直接声明,原类.m中实现;不需要自己的.m文件;
- 主要用于新增类的私有方法和私有变量.()
iOS 代理和block的理解相关推荐
- 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。
1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...
- Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理
Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...
- 利用代码分别实现jdk动态代理和cglib动态代理_代理模式实现方式及优缺点对比...
作者:爱宝贝丶来源:https://my.oschina.net/zhangxufeng/blog/1633187 代理模式最典型的应用就是AOP,本文结合主要讲解了代理模式的几种实现方式:静态代理和 ...
- 利用代码分别实现jdk动态代理和cglib动态代理_面试之动态代理
大家好!我是CSRobot,从今天开始,我将会发布一些技术文章,内容就是结合春招以来的面试所遇到的问题进行分享,首先会对知识点进行一个探讨和整理,在最后会给出一些面试题并作出解答,希望可以帮助到大家! ...
- Java中的原生动态代理和CGLIB动态代理的原理,我不信你全知道!
作者:CarpenterLee cnblogs.com/CarpenterLee/p/8241042.html 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询 ...
- cglib动态代理jar包_Java中的原生动态代理和CGLIB动态代理的原理,我不信你全知道!...
作者:CarpenterLee cnblogs.com/CarpenterLee/p/8241042.html 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询 ...
- spring 如何决定使用jdk动态代理和cglib(转)
Spring1.2: 将事务代理工厂[TransactionProxyFactoryBean] 或 自动代理拦截器[BeanNameAutoProxyCreator] 的 proxyTargetCla ...
- okhttp源码解析(五):代理和DNS
前言 之前我们分析了okhttp的重试机制,发现在获取可用地址的时候,都需要遍历一个路由选择器,里面保存了可用的地址,那么这些地址是从哪来的呢?这就是本篇分析的重点. 首先我们简单理解一下代理和DNS ...
- JDK动态代理和CGLIB动态代理的异同
代理模式的概念和静态代理之前的文章已经说过了,没看过的可以点这里. 动态代理意义在于生成一个占位(又称为代理对象),用来代理真实的对象,来控制真实对象的访问. 举个例子,现在有一家软件公司,公司里面有 ...
最新文章
- C++中为何构造函数不可是虚函数,而析构函数可以?
- POJ - 1236 Network of Schools(强连通缩点)
- mysql查询补丁更新_OS:服务器系统补丁及数据库补丁更新说明
- ndk学习20: jni之OnLoad动态注册函数
- CDH6 kafka如何彻底删除topic及数据
- vue 组件 全局组件和局部组件component
- Too many input arguments.
- Redlock(redis 分布式锁)原理分析
- linux系统原理论文3000字,linux操作系统(论文).doc
- 塔科夫帧数测试软件,逃离塔科夫如何优化游戏FPS_画面优化设置详解_52pk
- 怎么解决Xshell4终端中文乱码问题
- 射频微波芯片设计6:射频电路中的噪声概论
- 我的微信小程序登陆界面
- 论山寨手机与Android 【6】MTK手机的基带芯片
- 微信小程序真机调试步骤
- php文件迅雷下载不弹出来,javascript,_文件下载按钮被迅雷响应后,JS事件无法触发,javascript - phpStudy...
- java caller_java中callee获取caller
- 给你的手机加上安全保障,请设置SIM卡PIN码
- sqlserver 18456登录错误处理
- 【推荐系统论文精读系列】(八)--Deep Crossing:Web-Scale Modeling without Manually Crafted Combinatorial Features
热门文章
- 小火箭服务器订阅没显示节点,有zookeeper相关的大神么?使用ZKClient创建节点,但是服务器中并没有显示?...
- java excel 数组_Java将Excel解析为数组集合
- Java微信二次开发之14-自定义菜单及菜单响应事件的推送
- clusterProfiler安装或者升级中出现的版本问题
- Cglib代理原理剖析
- 后端代码一键打包上传服务器并重启服务
- 创建 /dev/video0 节点
- 阿里巴巴,果然开始拥有“预测未来”的能力了...
- [DForm]我也来做自定义Winform之另类标题栏重绘
- 易趣通网络电话 最新测试版本 怎么用