Block基础看它就够了

Block基本用法

"Block语法"

1.作为方法时

- (void)testGlobalBlock:(NSString*) url

                 success:(void(^)(BOOLisSuccess))success

                  failure:(void(^)(BOOLisSuccess))failure;

2.作为成员变量进行声明时

typedefvoid(^SUCCESSBLOCK)(BOOLisSuccess);

typedefvoid(^FAILEDBLOCK)(BOOLisSuccess);

@interfaceXXEngine()

@property(nonatomic,copy) SUCCESSBLOCK successBlock;

@property(nonatomic,copy) FAILEDBLOCK failedBlock;

@end

3.写在函数内部

void(^_block)() = ^{

_a =10;

};

内存五个区认识

这里先普及一个基本的5个概念,内存的5个区。否则在具体讲堆栈的时候怕大家会不理解。

作用名称

栈区(stack)由编译器自动分配释放,存放函数的参数值,局部变量的值等

堆区(heap)一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收

全局区(静态区)(static)全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放

文字常量区常量字符串就是放在这里的。程序结束后由系统释放

程序代码区存放函数体的二进制代码

使用场景

任务完成时回调处理

消息监听回调处理

错误回调处理

枚举回调

视图动画、变换

排序

Block原理

Block三种类型

作用名称

NSConcreteGlobalBlock全局静态,不访问外部变量的时候就是NSConcreteGlobalBlock

NSConcreteStackBlock保存在栈中,出花括号会被销毁

NSConcreteMallocBlock保存在堆中的block,当引用计数为0的时候会被销毁


ARC下判断原则

"Block语法"

造成循环引用的实例

@implementationPerson

{

int_a;

void(^_block)();

}

- (void)test

{

void(^_block)() = ^{

_a =10;

};}

@end

此时_a在用clang编译后可以很明显看到有会self的身影,所以此时我们可以将其理解成self.a(便于记忆),此时Person持有block,block持有self,造成了循环引用

解决方式

- (void)test

{

__weaktypeof(self) weakSelf =self;

void(^_block)() = ^{

weakSelf->a =10;

};}


经验谈之GCD/UIView的系统动画的Block中,为何可以写self?

因为self并没有对其进行持有,循环引用的原理是两个对象之间相互有持有关系,现在仅仅是GCD持有self,但是self并没有持有GCD,所以是没有问题的。(当GCD对象为其成员变量时才具有持有的关系)


结论

我们观察Block_byref_a_0结构体,这个结构体中含有isa指针,所以也是一个对象,它是用来包装局部变量a的。当block被copy到堆中时,Persontest_block_impl_0的拷贝辅助函数Persontest_block_copy_0会将Block_byref_a_0拷贝至堆中,所以即使局部变量所在堆被销毁,block依然能对堆中的局部变量进行操作。其中Block_byref_a_0成员指针forwarding用来指向它在堆中的拷贝

利用对象做Block

"Block语法"

现在有RequestObject和XXNetEngine两个文件.

1.RequestObject

#import

typedefvoid(^ReqSuccessBlock)(BOOLisSuccess);

typedefvoid(^FailedBlock)(BOOLisSuccess);

@interfaceRequestObject:NSObject

@property(nonatomic,copy) ReqSuccessBlock successBlock;

@property(nonatomic,copy) FailedBlock failedBlock;

@property(nonatomic,assign)NSIntegerCMD;

@property(nonatomic,assign)NSIntegerseq;

@end

2.XXNetEngine

#import"XXNetEngine.h"

#import"RequestObject.h"

@interfaceXXNetEngine()

@property(nonatomic,strong)NSMutableDictionary*requestDict;

@end

@implementationXXNetEngine

-(instancetype)init

{

if(self= [superinit]){

self.requestDict = [NSMutableDictionarydictionary];

}

returnself;

}

+(instancetype) sharedInstance

{

staticXXNetEngine* instance =nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

instance = [[XXNetEngine alloc] init];

});

returninstance;

}

-(void)requestData:(RequestObject*) reqObject

successBlock:(void(^)(BOOLisSuccess))successBlock

failureBlock:(void(^)(BOOLisSuccess))failureBlock

{

if( reqObject && successBlock && failureBlock ) {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{

//requestSeq是一个随机数

intrequestSeq = arc4random() %100;;

//网络操作

reqObject.successBlock = successBlock;

reqObject.failedBlock = failureBlock;

reqObject.seq = requestSeq;

[selfaddRequestItem:reqObject seq:requestSeq];

//模拟一个2秒的网络操作

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[selfdidReceiveData:reqObject.seq];

});});}}

- (void) didReceiveData:(NSInteger) seq

{

RequestObject *request = [selfgetRequestItem:seq];

if( request ) {

[selfremoveRequestItem:seq];

dispatch_async(dispatch_get_main_queue(), ^{

if(NULL!= request.successBlock ) {

request.successBlock(YES);

}});}}

//用命令字做参数传递

- (RequestObject *) getRequestItem:(NSInteger)seq

{

RequestObject *request =nil;

@synchronized(self) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

request = [self.requestDict objectForKey:numSeq];

}

returnrequest;

}

- (void) addRequestItem:(RequestObject *)request seq:(NSInteger)seq

{

@synchronized(self) {

if( request && (0!=seq) ) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

[self.requestDict setObject:request forKey:numSeq];

}}}

- (void) removeRequestItem:(NSInteger)seq

{

@synchronized(self) {

NSNumber*numSeq = [NSNumbernumberWithInteger:seq];

[self.requestDict removeObjectForKey:numSeq];

}}

@end

Delegate、Notification、Block的比较

名称优点缺点

Notification1.使用简单,代码精简。2.解决了同时向多个对象监听相应的问题。3.传值方便快捷,Context自身携带相应的内容。1.使用完毕后,要时刻记得注销通知,否则将出现不可预见的crash。2.key不够安全,编译器不会监测是否被通知中心正确处理。3.调试的时候动作的跟踪将很难进行。4.当使用者向通知中心发送通知的时候,并不能获得任何反馈信息。5.需要一个第三方的对象来做监听者与被监听者的中介。

Delegate1.减少代码的耦合性,使事件监听和事件处理相分离。2.清晰的语法定义,减少维护成本,较强的代码可读性。3.不需要创建第三方来监听事件和传输数据。1.实现委托的代码过程比较繁琐。2.当实现跨层传值监听的时候将加大代码的耦合性,并且程序的层次结构将变的混乱。3.当对多个对象同时传值响应的时候,委托的易用性将大大降低。

Block1.语法简洁,实现回调不需要显示的调用方法,代码更为紧凑。2.增强代码的可读性和可维护性。3.配合GCD优秀的解决多线程问题。1.Block中得代码将自动进行一次retain操作,容易造成内存泄露2.Block内默认引用为强引用,容易造成循环引用。

使用原则

如果方法过多,一般大于3个的时候,用delegate,因为此时用block,代码将很难维护。比如UITableViewDelegate等等UI组建,都是用的delegate。其他方式用block。

Notification能不用的时候尽量不用,缺点太多明显,增加调试难度。在工程大的情况下,极其难以维护。当然有些情况下也是必不可少的,比如观察者模式.

感谢:向晨宇Block入门

Block测试题:http://blog.parse.com/learn/engineering/objective-c-blocks-quiz/

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

推荐阅读更多精彩内容