Block学习笔记
2020-04-19 本文已影响0人
冷武橘
Block的初始化
block是一种特殊的数据类型,和Int,double,float....一样,可定义变量、作为参数、作为返回值。block可以用来保存一段代码,在恰当的时间再取出来调用,一般在动画、多线程、集合遍历、网络请求回掉中都经常见的到。
- block的声明和定义
1; //整形
2.1; //浮点型
@"2"; //字符串
^{
NSLog(@"block是一种特殊的数据类型");
}; //blockl类型;
block是一种特殊的数据类型,书写形式也就是在大括号前加上一个^,而大括号里可以保存代码段。
int a; //整形变量声明
float b; //浮点型变量声明
NSString *str ; //变量声明
void(^myblock)(); //block类型变量声明
a=12;
b= 11.2;
str=@"123";
myblock=^(){
NSLog(@"block类型的变量myblock赋值");
};
int c=12;
void(^hltblock)=^{
NSLog(@"block变量声明的同时并赋值");
};
在定义和初始化block时,我们要时刻记住block也是一种特殊的数据类型,其初始化方式和其他数据类型一样。
1.有参数的block
void(^hblock)(int,NSString*)=^(int a,NSString*b){
NSLog(@"%d %@",a,b);
};
hblock(2,@"qqq");
2.无参数的block
void(^hblock)()=^(){
NSLog(@"无参数的block");
};
void(^bblock)()=^{
NSLog(@"无参数的block,小括号可以省略");
};
3.有返回值的block
int(^block3)() = ^int{
return 3;
};
int(^block5)() = ^{
NSLog(@"block返回可以省略,不管有没有返回值,都可以省略
");
return 3;
};
NSLog(@"%d",block5());
// block快捷方式 inline
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
<#statements#>
};
Block内部访问外部变量
c=666;
int a =10;
__block int b=11;
void(^lwjblock)()=^(){
NSLog(@"%d",a);//默认情况下,block内部可以访问外面的变量
//a = 13;//默认情况下,block内部不能修改外面的局部变量
b=14;//给局部变量加上__block关键字,就可以修改局部变量了
NSLog(@"%d",b);
c=123;//全局变量可以修改
NSLog(@"%d",c);
};
lwjblock();
Block内部访问外部变量
- 值传递
//如果是局部变量,Block是值传递
int a = 3;
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();//block打印出的是3,是值传递
//block中使用的外面变量的值是拷贝过来的即值拷贝,所以在调用之前修改外界变量的值,不会影响到block中拷贝的值.
- 指针传递
// 如果是静态变量,全局变量,__block修饰的变量,block都是指针传递
__block int a = 3;
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();//这里调用block打印出的是5,是指针传递,可以直接影响变量的值
Block实战应用01-(保存代码)
应用场景描述:点击不同的cell跳转到不同的界面
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Settingitem : NSObject
/** 图片 */
@property (nonatomic, strong) UIImage *icon;
/** 标题 */
@property (nonatomic, copy) NSString *title;
/** 点击这一行要做的事情 */
@property (nonatomic, copy) void(^operation)(NSIndexPath *indexPath);
+ (instancetype)itemWithIcon:(UIImage *)icon title:(NSString *)title;
#import "Settingitem.h"
@implementation Settingitem
+ (instancetype)itemWithIcon:(UIImage *)icon title:(NSString *)title{
Settingitem *item = [[self alloc] init];
item.icon = icon;
item.title = title;
return item;
}
@end
#import <UIKit/UIKit.h>
@interface SettingController : UIViewController
@end
#import "SettingController.h"
#import "Settingitem.h"
@interface SettingController ()<UITableViewDelegate,UITableViewDataSource>
/** 数组总数 */
@property (nonatomic, strong) NSMutableArray *groups;
@end
@implementation SettingController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor=[UIColor whiteColor];
self.title=@"设置";
UITableView *tableview=[[UITableView alloc]initWithFrame:self.view.bounds style: UITableViewStylePlain];
tableview.delegate=self;
tableview.dataSource=self;
[self.view addSubview:tableview];
_groups = [NSMutableArray array];
Settingitem *item1 = [Settingitem itemWithIcon:[UIImage imageNamed:@"RedeemCode"] title:@"使用税换码"];
item1.operation = ^(NSIndexPath *indexpath){
NSLog(@"使用税换码");
};
Settingitem *item2 = [Settingitem itemWithIcon:[UIImage imageNamed:@"MorePush"] title:@"推送和提醒"];
//保存代码,保存要做的事
item2.operation = ^(NSIndexPath *indexpath){
NSLog(@"推送和提醒");
};
Settingitem *item3 = [Settingitem itemWithIcon:[UIImage imageNamed:@"handShake"] title:@"使用摇一摇机选"];
item3.operation = ^(NSIndexPath *indexpath){
NSLog(@"使用摇一摇机选");
};
[self.groups addObject:item1];
[self.groups addObject:item2];
[self.groups addObject:item3];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Settingitem *item = self.groups[indexPath.row];
if (item.operation) {
item.operation(indexPath);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.groups.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ID = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}
Settingitem *item = self.groups[indexPath.row];
cell.imageView.image = item.icon;
cell.textLabel.text = item.title;
return cell;
}
@end
Block实战应用02-(逆向传值)
#import "ViewController.h"
#import "ModalViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
ModalViewController *modalVc = [[ModalViewController alloc] init];
modalVc.view.backgroundColor = [UIColor brownColor];
modalVc.block = ^(NSString *value) {
NSLog(@"%@",value);
};
// 跳转
[self presentViewController:modalVc animated:YES completion:nil];
}
@end
#import <UIKit/UIKit.h>
@interface ModalViewController : UIViewController
//定义个block属性,以此为媒介进行传值
@property (nonatomic, strong) void(^block)(NSString *value);
@end
#import "ModalViewController.h"
@interface ModalViewController ()
@end
@implementation ModalViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 传值给ViewController
if (_block) {
_block(@"123");
}
}
@end
Block实战应用03-(作为参数使用)
需求:封装一个计算器,提供一个计算方法,怎么计算由外界决定,什么时候计算由内部决定.
#import <Foundation/Foundation.h>
@interface CacultorManager : NSObject
@property (nonatomic, assign) NSInteger result;
// 计算
- (void)cacultor:(NSInteger(^)(NSInteger result))cacultorBlock;
@end
#import "CacultorManager.h"
@implementation CacultorManager
- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
{
if (cacultorBlock) {
_result = cacultorBlock(_result);
}
}
@end
#import "ViewController.h"
#import "CacultorManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 把block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定
// 什么时候需要把block当做参数去使用:做的事情由外界决定,但是什么时候做由内部决定.
// 创建计算器管理者
CacultorManager *mgr = [[CacultorManager alloc] init];
[mgr cacultor:^(NSInteger result){
result += 5;
result += 6;
result *= 2;
return result;
}];
}
@end
封装一个网络请求工具类
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
@interface HttpTool : NSObject
/**
* 发送一个GET请求
*
* @param url 请求路径
* @param params 请求参数
* @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
* @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
*/
+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
/**
* 发送一个POST请求
*
* @param url 请求路径
* @param params 请求参数
* @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
* @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
*/
+ (NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
@end
#import "HttpTool.h"
@implementation HttpTool
+(void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
//1.获得请求管理者
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
//2.发送Get请求
[mgr GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
}
+(NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
//1.获得请求管理者
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
NSURLSessionDataTask *dataTask = [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
return dataTask;
}
@end
解决block循环引用
#import "Secviewcontroller.h"
#import "Person.h"
@interface Secviewcontroller (){
Person * _person;
}
@property(nonatomic,copy)void(^block)();
@property(nonatomic,strong)NSString *name;
@end
@implementation Secviewcontroller
/*
循环引用:我引用你,你也引用,就会造成循环引用,双方都不会被销毁,导致内存泄露问题
block造成循环利用:Block会对里面所有强指针变量都强引用一次
解决循环引用: 创建一个弱指针,如果外部对象是弱引用那么内部会自动生成一个弱引用,引用着外部对象。关键字:__weak
*/
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor=[UIColor whiteColor];
[self test2];
}
//解决循环引用
- (void)test1{
/*理解self:在当前指的是一个 Secviewcontroller对象,
即 :Secviewcontroller *weakself=self;
默认指针变量都是强指针,即
__strong Secviewcontroller *weakself=self;
为了避免循环引用,我们需要把__strong指针变成弱指针,于是我们需要这样就接受拿到self, 即
__weak Secviewcontroller *weakself=self;
*/
__weak Secviewcontroller *weakself=self;
self.block=^(){
NSLog(@"%@",weakself.name);
};
}
- (void)test2{
__strong Person *p = [[Person alloc] init];
__weak Person *weakperson=p;
p.personblock=^(){
NSLog(@"%@",weakperson.name);
};
}
//typeof(x) 函数动态根据x判断x的真实类型
- (void)commara{
int a = 10;
typeof(1) b =30;
NSLog(@"a %d b %d",a, b);
__weak typeof(self)weakself = self;
//typeof(self)相当于Secviewcontroller *
Person *p = [[Person alloc] init];
__weak typeof(p)weakperson = p;
NSLog(@"%@",[weakperson class]);
//typeof(self)相当于Person *
}
- (void)test3{
Person *p = [[Person alloc] init];
__weak typeof(p)weakperson = p;
p.personblock=^(){
NSLog(@"%@",weakperson.name);
};
__weak typeof(self)weakself = self;
self.block= ^(){
NSLog(@"%@",weakself);
};
}
//控制器只有被销毁时,才会被调用。(即循环引用的情况下,不会被调用)
-(void)dealloc{
NSLog(@"被释放销毁了");
}
@end