一 Block是什么?


我们使用^运算符来声明一个Block变量,而且在声明完一个Block变量后要像声明普通变量一样,后面要加;

  • 声明Block变量
int (^block)(int) = NULL;

Block变量的语法

数据返回值类型 (^变量名)(参数列表) = NULL

  • 赋值Block变量
block = ^(int m) {return m * m;
};

  • 使用Block变量
// 通过使用block变量,计算整型常量10的平方,并且打印在控制器输出NSLog(@"10的平方是:%d",block(10));

示例代码:

//
//  ViewController.m
//  BlockDemo
//
//  Created by lovestarfish on 15/11/16.
//  Copyright © 2015年 S&G. All rights reserved.
////不是block内部不能用self.也不是内部用了self就循环引用
#import "ViewController.h"//对block类型重命名,也就是把NSString*(^)(NSString*,NSString*)重命名
typedef NSString*(^YouBlock4)(NSString*,NSString*);@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self learnBlock];
}- (void)learnBlock {// ^代表就是block,代码块int a;a = 10;//block很像一个函数,可以有参数,可以有返回值//需要调用的时候,我们就去调用//1. 无参数无返回值void(^myBlock1)() = ^{NSLog(@"无参数无返回值的block");};//调用block
    myBlock1();//2. 有参数无返回值void(^myBlock2)(int,int) = ^(int a,int b){NSLog(@"%d",a + b);};//调用blockmyBlock2(10,9);//3. 无参数有返回值NSString* (^myBlock3)() = ^{return @"无参数有返回值的block";};//调用blockNSString *result = myBlock3();NSLog(@"%@",result);//4. 有参数有返回值NSString* (^myBlock4)(NSString *,NSString*) = ^(NSString *str1,NSString *str2){return [str1 stringByAppendingString:str2];};//调用blockNSString *result2 = myBlock4(@"hell",@"o");NSLog(@"%@",result2);//5. block类型重命名YouBlock4 bb = ^(NSString *str1,NSString *str2){return [str1 stringByAppendingFormat:@"-----%@",str2];};NSLog(@"%@",bb(@"ni",@"hao"));
}@end

通过以上代码可以得知,Block变量的使用步骤,类似于函数的步骤

  • 首先都要声明(声明函数,声明block变量);
  • 然后都要进行实现(实现函数,为block变量赋值实现过程);
  • 最后都要进行调用才能实现具体功能 

二 如何直接使用Block参数


  • 数组排序
    // 1.1 声明数组变量NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:@"5",@"2",@"3",@"9",@"7", nil];// 1.2 直接用block进行数组升序排序[mutableArray sortUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {// 将两个参数转换为字符串的对象NSString *value1 = (NSString *)obj1;NSString *value2 = (NSString *)obj2;// value1与value2两个对象的比较结果直接返回return [value1 compare:value2];}];// 1.3 打印可变数组变量NSLog(@"%@",mutableArray);

  • 简单的网络异步请求
    // 2.1 声明网络地址对象NSURL *url = [NSURL URLWithString:@"http://m.kuaidi100.com/query?type=quanfengkuaidi&postid=720140702702"];// 2.2 根据网络地址对象,声明网络请求对象NSURLRequest *request = [NSURLRequest requestWithURL:url];// 2.3 直接使用block变量完成链接成功后的数据返回功能[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {// 将二进制数据使用utf8编码转换成相应类型的对象NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];// 打印链接完成后的结果NSLog(@"%@",dic);}];

三 深入理解Block语法


在本节,主要去介绍的是使用 __block 修饰的变量能够完成的作用

先看一个例子

    // 1.声明一个局部整型变量int intValue = 3;// 2.声明一个返回值为int,一个int参数的block变量int (^block)(int) = ^(int m) {return m * intValue;};// 3.调用block变量,5作为参数之后的结果NSLog(@"block(5) = %d",block(5));

在本例中,intValue 变量称为block执行过程中的外部变量,在block执行过程中可以直接使用该外部变量.

再看一个例子

    // 1.声明一个局部整型变量int intValue = 3;// 2.声明一个返回值为int,一个int参数的block变量int (^block)(int) = ^(int m) {intValue++;return m * intValue;};// 3.调用block变量,5作为参数之后的结果NSLog(@"block(5) = %d",block(5));

在这个例子中,编译器编译后发现有红色错误,错误如下图:

为什么会出现不能被赋值的错误提示呢?

  • Block在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝
  • 在block块内使用只读拷贝

为了避免上述错误,就要使用__block修饰符来修饰外部变量,用来通知编译器该外部变量 intValue 与 block 中的 intValue 指的是同一块内存地址,而不需要内存拷贝

如下例:

    // 1.将intValue局部整型变量使用__block修饰符进行修饰__block int intValue = 3;// 2.声明一个返回值为int,一个int参数的block变量int (^block)(int) = ^(int m) {intValue++;return m * intValue;};// 3.调用block变量,5作为参数之后的结果NSLog(@"block(5) = %d",block(5));

四 使用Block要注意的内存问题

使用 weak-strong dance技术来避免循环引用

举例如下:

//
//  ViewController.m
//  BlockDemo
//
//  Created by lovestarfish on 15/11/16.
//  Copyright © 2015年 S&G. All rights reserved.
////不是block内部不能用self.也不是内部用了self就循环引用
#import "ViewController.h"@interface ViewController ()@end@implementation ViewController{id observer;
}- (void)viewDidLoad {[super viewDidLoad];// 添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {NSLog(@"%@",self);}];
}/***  当视图控制器对象销毁时,移除观察者*/
- (void)dealloc {if (observer) {[[NSNotificationCenter defaultCenter] removeObserver:observer];}
}@end

在上面代码中,我们向通知中心注册了一个观察者,然后在dealloc时解除该注册,一切看起来正常.但是里面有两个问题:

在消息通知 block 中引用了 self, 在这里 self 对象被 block 保留一次,而 observer 又 retain 该 block 的一份拷贝,通知中心又持有 observer . 因此只要 observer 对象还没有被解除注册, block 就会一直被通知中心持有,从而 self 就不会被释放, 其 dealloc 就不会被调用.而我们却又期望在dealloc中通过 removeObserver 来解除注册以消除通知中心对 observer/block 的保留次数

同时,observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用

// // ViewController.m // BlockDemo // // Created by lovestarfish on 15/11/16. // Copyright © 2015年 S&G. All rights reserved. // //不是block内部不能用self.也不是内部用了self就循环引用 #import "ViewController.h" @interface ViewController () @end @implementation ViewController { id observer; } - (void)viewDidLoad { [super viewDidLoad]; // 先声明一个weak弱对象 __weak ViewController *wSelf = self; // 添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象 observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { // 在block的执行过程中,使用强对象对弱对象进行引用 ViewController *bSelf = wSelf; if (bSelf) { NSLog(@"%@",bSelf); } }]; } /** * 当视图控制器对象销毁时,移除观察者 */ - (void)dealloc { if (observer) { [[NSNotificationCenter defaultCenter] removeObserver:observer]; } } @end

  • 在 block 之前定义对 self 的一个弱引用 wSelf, 因为是弱引用,所以当 self 被释放时 wSelf 会变为 nil ;
  • 在 block 中引用该弱引用,考虑到多线程情况,通过使用强引用 bSelf 来引用该弱引用,这时如果 self 不为 nil 就会 retain self,以防止在后面的使用过程中self 被释放
  • 在之后的 block 块中使用该强引用 bSelf, 注意在使用前要对 bSelf 进行了 nil 检测,因为多线程环境下在用弱引用 wSelf 对强引用 bSelf 赋值时,弱引用 wSelf 可能已经为 nil 了

通过这种 weak-strong 手法,block就不会持有self 的引用,从而打破了循环引用

转载于:https://www.cnblogs.com/lovestarfish/p/4995189.html

iOS开发 -------- Block技术中的weak - strong相关推荐

  1. iOS开发常用技术底层实现(精简概述)

    (1)RunTime总结: oc动态性, 运行时将代码转化为runtime的C代码 RunTime运行流程: 生成对应objc_msgSend方法 isa指针查看当前类有没有这个方法, 之后寻找父类, ...

  2. iOS开发 蓝牙技术4.0详解

    前言 前端时间,同学在做项目过程中遇到关于蓝牙方面的问题,今天我就给大家进行详细的进行讲解下蓝牙在iOS开发中的具体实现.在介绍蓝牙前,大家要搞清楚什么是蓝牙? 什么是蓝牙? 随着蓝牙低功耗技术BLE ...

  3. 浅谈设计模式在iOS开发实战项目中的应用

    在我们日常的开发中设计模式伴随着项目的各个模块,巧妙地使用设计模式可以让我们写出更高效,简洁,优美的代码.可是因为对于设计模式的不熟悉,很多高效的设计模式并没有被很好地使用起来,而最近也正好在revi ...

  4. iOS开发——高级技术内购服务

    内购服务 大家都知道做iOS开发本身的收入有三种来源:出售应用.内购和广告.国内用户通常很少直接 购买应用,因此对于开发者而言(特别是个人开发者),内购和广告收入就成了主要的收入来源.内购营销模式,通 ...

  5. iOS开发常见技术链接分享

    1.iOS中打包成IPA包的四种方法 http://www.jianshu.com/p/dd2b66cbf097 2.斯坦大学公开课iOS http://open.163.com/special/op ...

  6. iOS开发 - 在实战中挖掘之线程间的通信方式

    技术这行怎么变的高大上呢?那一定是抛出一个个的专有名词,很多时候,我们在谈论技术的时候,往往忘记了技术本身的作用是什么?我不能说这有多不好,但多少还是会有失偏颇. 今天我们要说的内容是线程间通信,说得 ...

  7. (0022)iOS 开发之@property的属性Weak Strong的深入学习

    最近做项目发现经常有一些疑惑,发现一些天天写的代码理解的不是很清楚,于是准备对一些问题进行彻底的总结.深究,以此夯实基础!记录在案. 1.@property 的介绍: 与@synthesize配对使用 ...

  8. IOS开发 Block的学习

    苹果公司正在大力推广Block块语法的使用,据说Block会迟早取代一般协议代理的使用. Block最大的作用是函数回调,简化代码. 在ios中,将blocks当成对象来处理,它封装了一段代码,这段代 ...

  9. iOS开发—block介绍

    - (void)viewDidLoad {[super viewDidLoad];NSLog(@"我在玩手机");NSLog(@"手机没电了");[self c ...

最新文章

  1. js取一定范围内的随机整数
  2. Node.js 究竟是什么?(zz)
  3. linux下c中嵌套正则表达式
  4. 混合模型的推荐算法(ACM暑校-案例学习)
  5. 墙裂推荐!顶级赛事CCF BDCI即将开赛!
  6. LibreOJ - 3083 与或和(单调栈+位运算)
  7. vb net excel 剪贴板 粘贴_12-2-Excel快速编辑行列的10条经验
  8. tkinter的GUI设计:界面与逻辑分离(三)-- 多页面
  9. java跨系统和跨域_java web服务解决跨域问题
  10. android4.4 ssl版本查看,OkHttp在4.4及以下不支持TLS协议的解决方法
  11. openresty组成和技术特点
  12. win10计算机策略禁止用户安装,win10系统软件无法安装显示被组策略阻止的操作办法...
  13. html如何制作图片蒙版,如何制作遮罩蒙版手机照片?详细图文教程
  14. PhotoSweeper X for Mac(重复照片清理工具)
  15. java背单词软件_背单词的java小软件
  16. __filename意思
  17. 变量值互换自定义函数swap()的使用
  18. 一个大数据架构师应该掌握的技能
  19. MyBatis 03 动态SQL
  20. 广西机电职院计算机系,广西机电职院崇左东盟学院办学点揭牌仪式暨2019级大专班开学典礼在东盟学院隆重举行...

热门文章

  1. 将Capicom调用代码封装到ActiveX——解决javascript调Capicom读取数字证书信息时,IE弹出安全提示的问题...
  2. 配置NAT超载(NAPT)
  3. 如何:在 Windows 窗体 ListView 控件中启用平铺视图 【转载】
  4. 转贴: mysql-5.7.20 编码由 utf8 改为 utf8mb4
  5. 如何将树莓派设置为WiFi热点
  6. 银行对公业务结构图梳理
  7. ArcGIS 栅格函数在线调用详解
  8. Python进行websocket接口测试
  9. Unity跨iOS、Android平台使用protobuf-net的方法
  10. 游戏开发经验分享:我所理解的打击感