Objective-C中 Block 在iOS在4.0版本的使用

  • 了解何谓block。
  • 了解block的使用方法。

Block 是iOS在4.0版本之后新增的程序语法.

在iOS SDK 4.0之后,Block几乎出现在所有新版的API之中,换句话说,如果不了解Block这个概念就无法使用SDK 4.0版本以后的新功能,因此虽然Block本身的语法有点难度,但为了使用iOS的新功能我们还是得硬着头皮去了解这个新的程序概念。

一、看一看什么是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));

  注意,到目前我们应该有发现block变量的使用步骤,有类似于函数的步骤

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

二、看一看如何直接使用block参数

  数组排序

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

  简单的网络异步请求

    //声明网络地址对象
    NSURL *url = [NSURL URLWithString:@"http://www.qq.com"];    
    //根据网络地址对象,声明网络请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];    
    //直接使用block变量完成链接成功后的数据返回功能
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {        //将二进制数据使用utf8编码转换成字符串对象
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];        
        //打印链接完成后的结果
        NSLog(@"%@",result);
        
    }];

  可以看出ios平台中的很多功能都已经集成了Block语法的处理方法.

三、看一看深入理解Block语法

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

  先来看一个例子。

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

  在上面的例子中,我们将intValue变量称为block执行过程中的外部变量,在block执行过程中可以直接使用该外部变量。

  再看一个例子。 

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

  在上面的例子中,我们编译程序后发现编译器会有红色错误,错误提示为

Variable is not assignable (missing __block type specifier)

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

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

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

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

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

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

  举例如下

////  ViewController.m////  Created by lewis.//#import "ViewController.h"@interface ViewController ()@[email protected] ViewController
{    id observer;
}- (void)viewDidLoad
{
    [super viewDidLoad];    
    //添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象
    observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
        NSLog(@"%@",self);
    }];
}- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}//当视图控制器对象销毁时,移除观察者- (void)dealloc
{    if (observer) {
        [[NSNotificationCenter defaultCenter] removeObserver:observer];
    }
}@end

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

  • 在消息通知 block 中引用到了 self,在这里 self 对象被 block retain,而 observer 又 retain 该 block的一份拷贝,通知中心又持有 observer。因此只要 observer 对象还没有被解除注册,block 就会一直被通知中心持有,从而 self 就不会被释放,其 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心对 observer/block 的 retain。
  • 同时,observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。

解决方式如下.

////  ViewController.m////  Created by lewis.//#import "ViewController.h"@interface ViewController ()@[email protected] ViewController
{    id observer;
}- (void)viewDidLoad
{
    [super viewDidLoad];    
    //先声明一个weak弱对象
    __weak ViewController *wSelf = self;    
    //添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象
    observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note){        
        //在block的执行过程中,使用强对象对弱对象进行引用
        ViewController *bSelf = wSelf;        if (bSelf) {
            NSLog(@"%@",bSelf);
        }
    }];
}- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}//当视图控制器对象销毁时,移除观察者- (void)dealloc
{    if (observer) {
        [[NSNotificationCenter defaultCenter] removeObserver:observer];
    }
}@end

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

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

时间: 2024-10-01 07:49:59

Objective-C中 Block 在iOS在4.0版本的使用的相关文章

iOS中block类型大全

iOS中block类型大全 typedef的block 作为属性的block 作为变量的block 作为方法变量入参的block 作为方法参数的block 无名block 内联函数的block 递归调用的block 作为方法返回值的block 作为函数名的block(太过奇葩,完全不知道怎么用-_-!) iOS中block类型大全,码迷,mamicode.com

iOS中block的用法 以及和函数用法的区别

ios中block的用法和函数的用法大致相同 但是block的用法的灵活性更高: 不带参数的block: void ^(MyBlock)() = ^{}; 调用的时候  MyBlock(); 带参数的block: int ^(MyBlock)(int,int) = ^(int a,int b){return a+b;} 调用MyBlock(5,6); 将block当作某个类的属性的写法 typedef void (^BlockOption)(); @property (nonatomic,ass

IOS中Block的循环引用

@interface DemoObj() @property (nonatomic, strong) NSOperationQueue *queue; @end @implementation DemoObj - (instancetype)init { self = [super init]; if (self) { self.queue = [[NSOperationQueue alloc] init]; } return self; } - (void)dealloc { NSLog(@"

iOS 中Block以及Blocks的使用

一.ios中block的使用 Block可以帮助我们组织独立的代码段,并提高复用性和可读性.iOS4在UIKit中引入了该特征.超过100个的Apple API都使用了Block,所以这是一个我们必须开始熟悉的知识. Block是什么样的? 你可以使用^操作符来声明一个Block变量,它表示一个Block的开始. int num1 = 7; int(^aBlock)(int) = ^(int num2) { return num1+nunm2; }; 在如上代码中我们将Block声明为一个变量,

iOS中Block使用探索

Block介绍 Block在ios 4.0之后加入,并大量使用在新的ios api中.block是一个匿名的代码块,可以作为传递给其他对象的参数,并得到返回值.从本质上讲,block同其他普通的变量类似,只是其储存的数据是一个函数体.Block不只是针对Objective-C的专利,而是一种可以应用于C.C++和OBjective-C的语言层面的新特性.通过使用block,开发者可以将一段代码段像某一个数值一样当做参数传递给函数.同时,blocks也是Objective-C的一种对象,可以像其他

iOS中block用法之两个界面传值问题

Block的使用有很多方面,其中传值只是它的一小部分,但是很常用更实用,下面介绍Block在两个界面之间的传值用法: 先说一下思想: 首先,创建两个视图控制器,在第一个视图控制器中创建一个Label和一个Button,其中Label是为了显示第二个视图控制器传过来的字符串, Button是为了push到第二个界面. 第二个界面的只创建一个TextField,是为了输入文字,当输入文字并且返回第一个界面的时候(第二个视图将要消失的时候),就将这个 TextFiled中的文字传给第一个界面并且显示在

IOS中block的使用方法

X.1 初探Block 在这一小节我们先用一些简单范例来导入block的概念. X.1.1 宣告和使用Block 我们使用「^」运算子来宣告一个block变数,而且在block的定义最后面要加上「;」来表示一个完整的述句(也就是将整个block定义视为前面章节所介绍的简单述句,因为整个定义必须是一个完整的句子,所以必须在最后面加上分号),下面是一个block的范例: 1: int multiplier = 7 ; 2: int (^myBlock)( int ) = ^( int num) 3:

iOS中-Block使用

Block对象是 C 级别的语法和运行时特性.它们和标准 C 函数很类似,但是除了可执行代码外,它们还可能包含了变量自动绑定(栈)或内存托管(堆).所以一个block维护一个状态集(数据),它们可以在执行的时候用来影响程序行为. 你可以用 blocks来编写函数表达式,这些表达式可以作为 API 使用,或可选的存储,或被多个线程使用.Blocks作为回调特别有用,因为block携带了进行回调所需要的执行代码和执行过程中需要的数据. Blocks在GCC和Clang里面可用,它附带在 Mac OS

IOS中 Block简介与用法(一)

?Block简介: Block的实际行为和Function很像,最大的差别是在可以存取同一个Scope的变量值.Block实体形式如下: ^(传入参数列){行为主体}; Block实体开头是"^",接着是由小括号所包起来的参数列(比如 int a, int b, int c),行为主体由大括号包起来,专有名字叫做block literal.行为主体可以用return回传值,类型会被compiler自动辨别.如果没有参数列要写成: ^(void). 例如下面的一个例子: [cpp] vi