Block块

1、Blocks简介
Block字面意思就是代码块(含义) iOS4.0、Mac OS X 10.6开始Apple引入的特性(引入时间)
Block是Objective C语言中的对象 但是与NSObject有所区别 Block是特殊的Objective C对象 (block是OC的特殊对象)

Block 对象提供了一个使用 C 语言和 C 派生语言(如 Objective-C 和 C++)来创建表达式作为一个特别的函数。(block特殊之处)
在其他语言和环境中,一个block对象有时候被称为“闭包(closure)”。在这里,它们通常被口语化为”块(blocks)”,除非在某些范围它们容易和标准 C 表达式的块代码混淆。
对于闭包(closure),有很多定义,其中闭包就是能够读取其它函数内部变量的函数

“^”符号可以称为caret ['kærət] 也叫脱字符 插入符

block.png

返回值(^块对象名称)(参数列表类型) = ^(参数列表){块对象中的代码};

2、用处

1)简单的回调过程,不用再实现并调用某个函数 (UIView动画)
2)代码简洁,减少冗余代码
3)与GCD结合使用 爽爆了

使用:UIView动画、presentViewController、ASI

3、声明和创建Block
声明Block引用 无参无返回 无参有返回 有参无返回 有参有返回

定义Block

使用Block

typedef声明 简称typedef 为现有类型创建一个新的名字,或称为类型别名,在结构体定义,还有一些数组等地方都会用到

返回值或参数为Block的

snippet 代码片段

4、Block对变量存取管理
1)局部变量
局部变量,在Block中只读。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响它在Block中的值

2)__Block修饰的变量
如果要在block内修改block外声明的局部变量,那么一定要对该变量加__block标记

3)Static修饰符的或全局变量
因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量.

Block变量,被__Block修饰的变量称作Block变量。 基本类型的Block变量等效于全局变量或静态变量 但对象的block变量不会

5、Block的内存管理
非ARC下
Block是默认建立在栈上, 所以如果离开方法作用域, Block就会被丢弃

Block的copy、retain、release操作 不同于NSObject的copy、retain、release操作:

只要实现一个对周围变量没有引用的Block,就会显示为是NSGlobalBlock
如果其中加入了对局部变量的引用,就是NSStackBlock
如果你对一个NSStackBlock对象使用了Block_copy()或者发送了copy消息,就会得到NSMallocBlock

1)NSGlobalBlock:retain、copy、release操作都无效;
2)NSStackBlock:retain、release操作无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即使retain也没用。容易犯的错误是[mutableAarry addObject:stackBlock],(补:在ARC中不用担心此问题,因为ARC中会默认将实例化的Block拷贝到堆上)在函数出栈后,从mutableAarry中取到的stackBlock已经被回收,变成了野指针。正确的做法是先将[stackBlock copy]到堆上,然后加入数组:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock类型对象。
3)NSMallocBlock支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增加、减少计数。copy之后不会生成新的对象,只是增加了一次引用,类似retain;
4)Block_copy与copy等效,Block_release与release等效;
5)对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;
6)尽量不要对Block使用retain操作,不方便管理。

Block的使用:UIView动画、presentViewController、ASI

6、Block对objc对象的内存管理
staticObj、instanceObj、localObj、blockObj多种类型obj对象
主要是block被copy时其块中用到的变量的引用计数
1)非ARC
staticObj在内存中的位置是确定的,所以Block copy时引用计数不会改变。
instanceObj在Block copy时并没有直接让instanceObj对象本身引用计数加1,但却让self引用计数加1。所以在Block中可以直接读写instanceObj变量。
localObj在Block copy时,系统自动增加其引用计数。
blockObj在Block copy时引用计数也不会改变。
使用__block避免循环引用 __block 类 *对象 = self

void(^block)(void)= ^{
[blockSelf doSomething];
};

Tips:
内存主要分为
1.栈 - 由编译器自动分配释放 里面的变量通常是局部变量 函数参数等
2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 alloc
3.全局区(静态区 static),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束释放 static
People *p; People *p2 = nil;
4.另外还有一个专门放常量的地方。- 程序结束释放 NSString *lastName = @“xue”;
lastName = @“dkjs”;
5、方法区


Block的写法:

1.有返回值有参数的

int(^myBlock1)(int) = ^(int num){
    returen num;
}
//block的调用
myBlock1(3);

2.无返回值无参数的

//block的声明  如果没有参数声明时必须写(void) 实现的时候可以写(void)也可以不写
void(^myblock2)(void) =^(void){
    NSLog(@"我是joye");
};
myblock2();

3.无返回值有参数的

 //无返回值 有3个参数的block 多个参数要以逗号分隔
  void (^myblock3)(int,float,NSString*) =^(int a,float b,NSString*name){
    NSLog(@"%d----%f----%@",a,b,name);
};
myblock3(5,6.0,@"张三");

4.要定义block的全局变量的方法
#import <UIKit/UIKit.h> //用其代表在.h 文件中
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
void(^myblock4)(void);
UILabel *(^myblock5)(void);
}
@end
#import "AppDelegate.h" //用其代表在.m 文件中
myblock4= ^{
NSLog(@"123456");
};
myblock4();
myblock5 =^{
UILabel *label =[[UILabel alloc] init];
return label;
};
UILabel *label = myblock5();
5.当多次重复输入格式相同的块时 可以给这个类型起一个别名 方便创建相同类型的block 在.h中声明

//类型定义  相当于给某种类型 起了一个别名 方便我们创建相同类型block

#import <UIKit/UIKit.h>
typedef void(^totalBlock)(void);
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    totalBlock myblock6;
}
#import "AppDelegate.h"
//使用类型定义创建全局block
myblock6 =^{

};
myblock6();

6.类型定义 如果参数的位置不同 不能使用同一个block创建

#import <UIKit/UIKit.h>
//类型定义只能使用定义好的类型 如果参数位置不一样 也不能使用同一个block创建
typedef NSString*(^totalBlock1)(NSString*,int);
typedef NSString*(^totalBlock2)(int, NSString*);
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
#import "AppDelegate.h"
totalBlock1 myblock7 =^(NSString *name,int a){
    return name;
};
myblock7(@"joye",1)

block内存管理

1.在Block内部 使用 外部 局部变量 如果一个外部局部变量没有经过__block描述 就在内部使用 那么当前变量就会被copy一份新值

int a = 100;
a = 200;
void(^myBlock)(void)=^{
    NSLog(@"%d",a);
};
a = 300;
a = 400;
myBlock();

//输出结果 a 的值为200

2.如果不想在block内部copy 要用__block描述

__block int b = 1111;
b = 2222;
void (^myBlock2)(void)=^{
    NSLog(@"%d",b);
};
b = 3333;
myBlock2();
//输出结果 a 的值为 3333

3.block 使用全局变量 那么不会进行copy

{
  int c;
}

c = 1000;
c = 2000;
void(^myBlock3)(void)=^{
    NSLog(@"%d",c);
};
c = 3000;
myBlock3();

//输出的 c 的值为3000

4.被static描述变量是 不copy 使用原值

static int d = 123;
d = 321;
void(^myBlock4)(void)=^{
    NSLog(@"%d",d);
};
d = 456;
myBlock4();

//输出的 d 的值为123

要在 block 内部 修改外部局部变量 要加 ____block__ 或 ____weak__ 描述
在 block 内部修改全局变量和静态变量 不用加 ____block__

__block int e = 666;
void(^myBlock5)(void)=^{
    NSLog(@"%d",e);
    e = 999;
};
myBlock5();

总结:当变量被 __block 或者 static 描述 或者使用的变量是全局变量时 在block内部使用都不进行copy 而是使用原值


内存相关

内存分区:
栈:不需要程序员进行管理 基本数据类型
堆:需要程序员进行管理 对象类型
全局区(静态区) 全局和静态变量
常量区 NSString*str = @“123”;
方法区

//默认是在栈区创建Block,出了当前方法block会被系统释放
//__NSGlobalBlock__ 是在没有使用任何外部变量时block的类型
//__NSStackBlock__ 使用了外部变量后block的类型
//不管是 __NSGlobalBlock__ 还是 __NSStackBlock__ 都在栈区
//__NSGlobalBlock__ 使用retain copy release等内存管理的关键字 都是无效的
//__NSStackBlock__ 使用retain release依然无效 但是使用copy有效

//__NSMallocBlock__ 当block为 __NSStackBlock__ 类型时 进行copy后变成 __NSMallocBlock__ 类型
//__NSMallocBlock__ 是在堆上面创建的 可以对其retain copy release,但是进行这些内存操作后 引用系数一直为1 但不代表引用计数没有增加 不建议对其retain操作
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,B...
    smile刺客阅读 2,331评论 2 26
  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 3,757评论 0 23
  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 9,793评论 10 69
  • 一、Objective-C发展史 Objective-C从1983年诞生,已经走过了30多年的历程。随着时间的推移...
    没事蹦蹦阅读 5,814评论 12 34
  • Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。用过GCD就知道Block的精妙之处。...
    Coder_JMicheal阅读 718评论 2 1