首先两者作用是一样的,都是进行单一回调。不通的是,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--堆
  1. block内没有使用外部变量或是只使用了全局/静态变量时.存于全局代码区,为全局block;---(ARC和MRC下一致)
  2. 当使用外部变量时
    • MRC下,block代码存于栈区;如果此外部变量A存于栈区,那么A会被copy到block分配的栈区;如果A是存于堆区,那么A在block块内与快外相同.
    • ARC下,block代码存于堆区.如果此外部变量A存于栈区,那么A会被copy到block分配的堆区;如果A是存于堆区,那么A在block块内与快外相同.
  3. 如果需要修改外部变量,需要在变量前面声明__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使用技巧

  1. block结构快速显示:inlineBlock...(也可右下角自定义快速显示其他格式)
  2. Block作为方法参数时,最好把参数列表部分加上,这样后面调用方法时,会自动有格式;
  3. 做方法参数时,需要加上返回值类型;
  4. 做返回值时,先定义别名,最后别忘记执行返回值;
  5. 方法中,void(^)()表示block类型同int,做参和返回值;做实例变量
    @property (nonatomic, copy) void(^变量名)()
  6. 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.应用:
  1. 协议只声明多个方法,不实现, 不能定义属性;
  2. 只要遵守协议,就可以拥有协议的所有方法声明;
  3. 一个类遵守协议而实现的方法,声明和实现都会遗传给子类,而没有实现的方法声明会遗传给子类,即协议可以 继承 ;
  4. 协议和类可以多对多,而一个协议又可以继承其他一个或多个协议.
  5. 所有协议默认遵守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帮忙;
思路:
  1. 先定义一个协议.
  2. 定义代理类,遵守此协议.
  3. 主类定义限定此协议类型的属性.
  4. 主类中要有行为 来触发代理.
  5. 设置代理.

  6. 用父类还是id<协议>

  7. 不使用父类的原因:
  8. 如果抽象一个父类的话, 还是有局限性, 因为很多时候, 不同类是无法抽象出共同的父类
    的. , 不能多继承

3.Category

  1. 作用:在不修改原类的情况下扩展其他功能
  2. 目的:对类方法进行归类,便于分模块开发大型类,团队协作.
    声明:@interface 类名(分类名)
    实现:@implementation 类名
    使用原类直接调用
注意:1)分类不能扩展任何新的实例变量; 
  • 2)分类可以访问原类的成员变量;(相当于原类方法调用)
  • 3)如果分类中存在和原类同名方法,优先使用分类(功能更新);
  • 4)如果多个分类都有同名方法,调用最后一个参与编译的分类同名方法;在Compile Sources 文件编译可以看到的的顺序;

分类的非正式协议:(面试题)
就是NSObject(和系统类框架)的类别(分类)即系统类的分类,增加了所有类的功能;类别接口中指定的方法可能会或者可能不会被框架类实际地实现,而是被子类重写. 

分类的延展(匿名分类)Extendsion

延展是分类一个特例,匿名.且新添加的方法一样要予以实现
@interface MyClass () {float value;    //可以新增实例变量}
-(void)setValue:(float)newValue;
@end
使用:
  1. 可以在原类.h直接声明,原类.m中实现;不需要自己的.m文件;
  2. 主要用于新增类的私有方法和私有变量.()

iOS 代理和block的理解相关推荐

  1. 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。

    1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...

  2. Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理

    Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...

  3. 利用代码分别实现jdk动态代理和cglib动态代理_代理模式实现方式及优缺点对比...

    作者:爱宝贝丶来源:https://my.oschina.net/zhangxufeng/blog/1633187 代理模式最典型的应用就是AOP,本文结合主要讲解了代理模式的几种实现方式:静态代理和 ...

  4. 利用代码分别实现jdk动态代理和cglib动态代理_面试之动态代理

    大家好!我是CSRobot,从今天开始,我将会发布一些技术文章,内容就是结合春招以来的面试所遇到的问题进行分享,首先会对知识点进行一个探讨和整理,在最后会给出一些面试题并作出解答,希望可以帮助到大家! ...

  5. Java中的原生动态代理和CGLIB动态代理的原理,我不信你全知道!

    作者:CarpenterLee cnblogs.com/CarpenterLee/p/8241042.html 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询 ...

  6. cglib动态代理jar包_Java中的原生动态代理和CGLIB动态代理的原理,我不信你全知道!...

    作者:CarpenterLee cnblogs.com/CarpenterLee/p/8241042.html 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询 ...

  7. spring 如何决定使用jdk动态代理和cglib(转)

    Spring1.2: 将事务代理工厂[TransactionProxyFactoryBean] 或 自动代理拦截器[BeanNameAutoProxyCreator] 的 proxyTargetCla ...

  8. okhttp源码解析(五):代理和DNS

    前言 之前我们分析了okhttp的重试机制,发现在获取可用地址的时候,都需要遍历一个路由选择器,里面保存了可用的地址,那么这些地址是从哪来的呢?这就是本篇分析的重点. 首先我们简单理解一下代理和DNS ...

  9. JDK动态代理和CGLIB动态代理的异同

    代理模式的概念和静态代理之前的文章已经说过了,没看过的可以点这里. 动态代理意义在于生成一个占位(又称为代理对象),用来代理真实的对象,来控制真实对象的访问. 举个例子,现在有一家软件公司,公司里面有 ...

最新文章

  1. C++中为何构造函数不可是虚函数,而析构函数可以?
  2. POJ - 1236 Network of Schools(强连通缩点)
  3. mysql查询补丁更新_OS:服务器系统补丁及数据库补丁更新说明
  4. ndk学习20: jni之OnLoad动态注册函数
  5. CDH6 kafka如何彻底删除topic及数据
  6. vue 组件 全局组件和局部组件component
  7. Too many input arguments.
  8. Redlock(redis 分布式锁)原理分析
  9. linux系统原理论文3000字,linux操作系统(论文).doc
  10. 塔科夫帧数测试软件,逃离塔科夫如何优化游戏FPS_画面优化设置详解_52pk
  11. 怎么解决Xshell4终端中文乱码问题
  12. 射频微波芯片设计6:射频电路中的噪声概论
  13. 我的微信小程序登陆界面
  14. 论山寨手机与Android 【6】MTK手机的基带芯片
  15. 微信小程序真机调试步骤
  16. php文件迅雷下载不弹出来,javascript,_文件下载按钮被迅雷响应后,JS事件无法触发,javascript - phpStudy...
  17. java caller_java中callee获取caller
  18. 给你的手机加上安全保障,请设置SIM卡PIN码
  19. sqlserver 18456登录错误处理
  20. 【推荐系统论文精读系列】(八)--Deep Crossing:Web-Scale Modeling without Manually Crafted Combinatorial Features

热门文章

  1. 小火箭服务器订阅没显示节点,有zookeeper相关的大神么?使用ZKClient创建节点,但是服务器中并没有显示?...
  2. java excel 数组_Java将Excel解析为数组集合
  3. Java微信二次开发之14-自定义菜单及菜单响应事件的推送
  4. clusterProfiler安装或者升级中出现的版本问题
  5. Cglib代理原理剖析
  6. 后端代码一键打包上传服务器并重启服务
  7. 创建 /dev/video0 节点
  8. 阿里巴巴,果然开始拥有“预测未来”的能力了...
  9. [DForm]我也来做自定义Winform之另类标题栏重绘
  10. 易趣通网络电话 最新测试版本 怎么用