`
啸笑天
  • 浏览: 3461324 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

Block开发浅谈

阅读更多

 

一、block的定义及优点

Apple文档说:

A block is an anonymous inline collection of code, and sometimes also called a "closure".

Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持。从ios4.0,Mac_OSX v10.6开始就很好的支持Block。

在其他语言和环境中,更流行的把一个block对象称为闭包(在javascript,java,scale,groovy等语言中都有)。

项目中感觉使用Block最大的便利就是简化的回调过程。以前使用UIView的动画,进程要控制动画结束后进行相应的处理。iOS 4.0之后,UIView新增了对Block的支持,现在只要使用简单的一个Block代码就可以在写动画的代码部分直接添加动画结束后的操作。

二、block的声明和定义



 

ex:

c函数指针和blocks调用 

     int (*CFunc) (int a) //c函数指针
     int result = CFunc(10); 
     int (^BFunc)  (int  a) //blocks定义 
     int result = BFunc(10); 

 

注意 :在声明时一个没有使用任何参数的block必须在参数列表上面用void标明。 但定义时可以省略:

 

int (^myBlock)(void) = ^{  
    return 20130212;  
}; 

 

三、使用block

1、定义并调用block

如果你声明了一个block作为变量,你可以把它作为一个函数来使用

 

int (^oneFrom)(int) = ^(int anInt) { return anInt - 1; };
NSLog("1 from 10 is %d", oneFrom(10)); // Prints "1 from 10 is 9"

 

2、block用作方法、函数(多线程,动画)的参数

Cocoa提供了一系列使用block的方法。你可以把一个block作为方法的参数就像其他参数那样。下面是zon的一个例子

 

  items =  [items sortedArrayUsingComparator:^(id item1, id item2) {
                EPGItem *epg1 = item1;
                EPGItem *epg2 = item2;
                
                // NSComparisonResult is a typedef for int
                NSComparisonResult result = [[NSNumber numberWithFloat:[[epg2 score] floatValue]] compare:[NSNumber numberWithFloat:[[epg1 score] floatValue]]];
                if (result) {
                    return result;
                }
                return (NSComparisonResult)NSOrderedSame; // NSOrderedSame == 0

            }];

 

(NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr NS_AVAILABLE(10_6, 4_0);

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);

 

3、block代替delegate

简化的回调过程

 

typedef void (^SRRefreshBlock)(NLPullRefreshView* sender);
@interface NLPullRefreshView : UIView {
@property (nonatomic, copy)  SRRefreshBlock    block;
@property(nonatomic,weak) NSObject <NLPullRefreshViewDelegate>  *delegate;
@end
@protocol NLPullRefreshViewDelegate
- (void)nlRefreshTableHeaderDidTriggerRefresh:(NLPullRefreshView*)view;
@end
 
@implementation NLPullRefreshView{
- (void)pullApart:(NLPullRefreshView*)refreshView
{
    if ([_delegate respondsToSelector:@selector(nlRefreshTableHeaderDidTriggerRefresh:)]) {
        [(id)_delegate performSelector:@selector(nlRefreshTableHeaderDidTriggerRefresh:)
                            withObject:self
                            afterDelay:0.0];
    }
    if (_block) {
        _block(self);
    }
}
}

 

四、block注意点

1、block文本(即, ^{ ... }) 是表示block的局部栈数据结构(stack-local data structure)的地址.

所以这些栈数据仅在当前声明的范围内有效,必须避免如下的使用:

 

void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
 for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
 // WRONG: The block literal scope is the "for" loop
}
}
void dontDoThisEither() {
 void (^block)(void);
int i = random():
 if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause
}
// ...
}

 

 

2、

  一个Block的内部时可以引用自身作用域外的变量的,包括static变量(RW),extern变量(RW)或自由变量(R),对于自由变量,在Block中只读的。在引入block的同时,还引入了一种特殊的__block关键字变量存储修饰符,指自由变量拥有读写权限:

__block int x = 123;
// x lives in block storage
 void (^printXAndY)(int) = ^(int y) {
 x = x + y;
 NSLog("%d %d\n", x, y);
 };

但是使用__block的变量有两个限制:它们不能是可变长的数组,并且它们不能是包含有C_9_9_可变长度的数组变量的数据结构。 

 

3、block与内存管理 

无ARC:

block调用的时机可能是随意的,既然block可以引用外部环境,为了保证block被调用的时候当时的环境变量不被释放,被block引用的变量都会被自动隐式retain一次,这样至少可以保证我们的调用是有效的,但他也隐藏了一个问题:retain cycle!

(

防止retain cycle

方法1:尽量保持子对象引用父对象的时候使用弱引用

方法2:及时地将造成retain cycle中的一个变量设置为nil,将环break掉

)

 

DoSomethingManager *manager = [[DoSomethingManager alloc] init];
manager.complete = ^{
//...complete actions
 [manager otherAction];
 manager.complete = nil;
 [manager release];
 };

 

manager的complete被设置为nil,如此一来retain cycle也被破坏掉,前提是你确实不需要再次回调block了。

 

使用ARC:

 

ARC中,变量可以用三个关键字修饰:

__strong: 赋值给这个变量的对象会自动被retain一次,如果在block中引用它,block也会retain它一次。__unsafe_unretained: 赋值给这个变量不会被retain,也就是说被他修饰的变量的存在不能保证持有对象的可靠性,它可能已经被释放了,而且留下了一个不安全的指针。不会被block retain。 __week:类似于__unsafe_unretained,只是如果所持有的对象被释放后,变量会自动被设置为nil,这样更安全些,不过只在IOS5.0以上的系统支持,同样不会被block retain。

另外我们也可以用 __block 关键字修饰一个变量,表示这个变量能在block中被修改(值修改,而不是修改对象中的某一个属性,可以理解为修改指针的指向)。会被自动retain。

于其他变量不同的是被 __block 修饰的变量在块中保存的是变量的地址。(其他为变量的值)

DoSomethingManager *manager = [[DoSomethingManager alloc] init];
manager.complete = ^{
 //...complete actions
 [manager otherAction];
manager.complete = nil;
 };
 没什么问题,只是去掉了ARC中禁止的release。

 

当然,我们也可以这么写:

 

__block DoSomethingManager *manager = [[DoSomethingManager alloc] init];
 manager.complete = ^{
//...complete actions [
manager otherAction];
manager = nil;
 };
 如果不用ARC,manager不会在block中被retain,但是采用了ARC就有些复杂了。block会retain manager变量,但是,由于__block变量保存更为底层的变量地址, 因此当此变量被指向其他对象时,block便不对原来的对象负责,引发的结果就是之前对象被release掉,retain cycle被破坏。

但是,有一个问题就是,object的释放动作是在Block内部执行,如果Block没有被执行的话,循环参照一直存在。

 

另一种方案算是目前比较好的解决方案,就是让Block的参照变为弱参照 __weak

 

MyObject *object = [[MyObject alloc] init];
 object.str = @"hoge";
 __weak MyObject *weakObject = object;
object.block = ^{  
  MyObject strongObject = weakObject; 
   if (strongObject) {       
 NSLog(@"block: str=%@", strongObject.str);  
  }
 };
 考虑到异步通信时Blocks的使用情况,weak变量weakObject有可能随时变为nil,所以类似于下面先变为strong变量,并检查是否为nil的处理方式应该更安全。

 

 

 

  • 大小: 283.4 KB
分享到:
评论
6 楼 啸笑天 2014-01-15  
typedef void (^AddPlayerBlock)(Player *player);   //声明的时候参数不可以省略
5 楼 啸笑天 2014-01-15  
__typeof (&*self) __weak weakSelf = self;
4 楼 啸笑天 2014-01-15  
http://blog.sina.com.cn/s/blog_76703a360101hl7k.html
3 楼 啸笑天 2013-06-06  
http://blog.parse.com/2013/02/05/objective-c-blocks-quiz/
2 楼 啸笑天 2013-06-06  
http://www.cnblogs.com/biosli/archive/2013/05/29/iOS_Objective-C_Block.html
1 楼 啸笑天 2013-04-10  
typedef void (^IndexChangeBlock)(NSInteger index);
@property (nonatomic, copy) IndexChangeBlock indexChangeBlock;

相关推荐

    浅谈iOS 对于block的一点理解

    在iOS开发中,Block的应用非常广泛,尤其是在处理异步操作、回调、GCD(Grand Central Dispatch)等场景。 首先,Block是一种对象,它可以像变量一样被赋值、传递和存储。Block可以捕获和存储它所在作用域内的局部...

    浅谈css溢出机制探究

    在实际开发中,如果遇到内容溢出却没有被祖先元素的overflow:hidden影响,可能是因为内容元素的直接或间接containing block不是祖先元素,或者是因为设置了position:absolute使得元素脱离了常规的文档流。...

    深入浅出谈CUDA.pdf

    CUDA是NVIDIA推出的并行计算平台和编程模型,全称Compute Unified Device Architecture,即...这种深入浅出的介绍方式,旨在帮助那些希望入门CUDA的开发者,通过亲身体验和实际编程示例,更直观地掌握CUDA的使用方法。

    浅谈在Windows Phone 7 中ListBox的使用

    在Windows Phone 7开发中,ListBox是一个非常重要的控件,用于展示一系列可滚动的项目列表。这个控件继承自ItemsControl,允许开发者通过Items或ItemsSource属性来填充内容。本文将深入探讨ListBox的使用,包括数据...

    深入浅出谈CUDA

    ### 深入浅出谈CUDA:关键技术与应用解析 #### CUDA概述 CUDA(Compute Unified Device Architecture)是由NVIDIA公司推出的通用并行计算架构。它允许开发者使用C、C++等高级编程语言来编写能够在GPU(图形处理器)...

    浅谈机械CAD绘图技巧.pdf

    AutoCAD软件,由美国Autodesk公司开发,自1982年推出以来,已成为机械设计行业中应用最广泛的绘图软件之一。它具备完善的图形绘制功能和强大的图形编辑功能,支持强大的数据交换能力以及便捷的多种图形格式转换能力...

    浅谈STM32核心板原理图设计.pdf

    若要取消系统自带的标题栏,可在“Sheet Options”标签页中取消勾选“TitleBlock”项。 原理图设计的下一步是加载元件库。在软件界面右下角点击“Libraries”,弹出元件库安装对话框,点击“Installed”后选择所需...

    LinuxUSB架构浅谈-guolele出品.pdf

    对于HUB设备,Linux使用`hub_probe`进行初始化,包括分配缓冲区,获取HUB描述符,设置接口,创建中断URB(USB Request Block)以处理端口状态变化。`hub_configure`和`hub_disconnect`处理设备连接和断开,`hub_...

    浅谈超大型Oracle数据库的基础设计和优化设计.pdf

    Oracle数据库是一种广泛应用于商业领域的大型关系型数据库管理系统,它由美国甲骨文公司开发,以其强大的数据处理能力和海量数据存储而著称。由于其优越的性能,在处理大型数据集时被越来越多的用户采纳,并成为众多...

    浅谈LabVIEW在远程虚拟化学实验室的应用.docx

    - **框图程序(Block Diagram)**:这是VI的图形化源代码,通过图形语言控制前面板对象并实现功能。框图中包括了控制器和指示器的连线端子,以及函数、结构和连线等编程元素。 - **图标和连接器窗格(Icon and ...

    深入浅出谈 CUDA (好)

    ### 深入浅出谈CUDA #### 一、引言 随着计算机技术的发展,图形处理器(Graphics Processing Unit, GPU)不仅被广泛应用于图形渲染领域,更因其强大的并行处理能力而逐渐成为通用计算的重要组成部分。NVIDIA推出的...

    浅谈应用CAD环境下点、线、面命令制作地形图图例的方法.pdf

    本文将深入探讨如何利用AutoCAD环境下点、线、面命令制作地形图图例的方法,这些命令包括块(Block)、线型(Linetype)、填充(Hatch)等。 首先,地形图图例主要包含点符号、线符号和面符号。这些符号在AutoCAD中...

    浅谈LINUX操作系统中Samba3.0服务器实战.pdf

    Samba基于Session Message Block (SMB)协议,允许Linux主机与Windows网络中的设备进行通信,极大地扩展了Linux服务器的功能。 首先,安装Samba3.0服务器需要在Linux上配置合适的硬件和软件环境。例如,文中提到的...

    浅谈现场总线开放系统的系统集成与应用集成.rar

    标准功能块(Standard Function Block)是现场总线系统中预定义的控制逻辑模块,例如PID控制器、报警器等。它们简化了系统设计,因为工程师可以使用这些现成的功能块组合出所需的控制策略,而无需从头编写代码。这样...

    深入浅出谈CUDA技术

    在CUDA的编程模型中,包括几个基本概念:主机(Host)和设备(Device),内核(Kernel),线程块(Block)和线程网格(Grid)。CPU通常充当主机角色,而GPU作为设备来执行任务。内核是CUDA程序中的函数,由主机发起...

    GPU计算]深入浅出谈CUDA技术

    NVIDIA提供了丰富的CUDA开发工具和文档资源,支持包括Windows和Linux在内的多种平台,使得开发者能够更加方便地利用CUDA进行高性能计算。 综上所述,CUDA技术是高性能并行计算的一个重要工具,它为开发者提供了一种...

Global site tag (gtag.js) - Google Analytics