1 block块的感性认识

块这种语法,在其他语言中叫做闭,把一定的变量关闭到一定的作用域之内。

块可以帮助开发者封装了指令,病切内联在其他代码里,用于获取作用域的值,产生的结果对象与其他对象一样,可以进行复制,也可以进行值传递

块的奇妙之处,可以块取得外面的作用域的变量的值。通常没必要将所有的参数都打包在一个参数列表里面,可以只是简单设定作用域,使用里面的变量就可以。

2 block语法

int captured =1 	
int (^offsetter)(int) = ^(int x){return x + captured ;} ;

第一行创建一个本地变量captured
第二行 声明一个命名为offsetter的变量,同时也是一个块,创建或者定义一个块使用^,这个块返回一个整数值,并使用一个整形的参数。
在右边,进行块的定义使用(^符号),看起来有些类似C函数的定义:指定参数X,括号里面是块体。 image

注意:
其一,并没有指明块返回的类型,但编译其能根据返回语句进行判断;
其二,在块内部引用了变量captured。说此处获取的captured变量在块内部的值。这就是块的强大特性之一。

3 调用block

int answer = offsetter(2)

注意这时返回值是3(2+1=3)如果改变captured的值后在才调用 会怎么样呢?

captured =64

answer =offsetter(2)

这是返回值还是 3

,这是因为captured的值只在定义块是获取,不能在块的外面改变captured的值反作用域块内部,当然也不能在块的内部改变captured的值,为了实现在块内部改变变脸的值,需要使用__block的类型指定语句。

-(void) testBlock {
	 int captured =1 ;
	 int (^offsetter)(int) = ^(int x) {return x +  captured ; } ;
	 
	 NSLog(@" %d" , offsetter(2)) ;
	 captured = 64 ;
	 NSLog(@" %d" , offsetter(2)) ;
 }

-(void) testModifyBlock {
    __block int captured = 1 ;  //这样可以修改了,获得最近的修改值
    NSLog(@"[testModifyBlock] captured= %d" , captured) ;
    int (^offsetter)(void)   = ^(void)  { captured =2 ; return 1 ;} ;

    offsetter() ;

  NSLog(@"[testModifyBlock] captured= %d" , captured) ;
}

4 block 与 self和属性

//.h
@property (nonatomic , copy) NSString *stringProperty  ;
//.m
void (^correctBlockObject)(id) = ^(id self) {
    NSLog(@"self =%@" , self)  ;
    //直接读写取属性都是错误的 ,要通过setter、getter函数
   // self.stringProperty = @"hello world";  //编译错误
    [self setStringProperty:@"hello world"] ;
    NSLog(@"self.self.stringProperty  =%@" , [self stringProperty])  ;
} ;

5 block 与 强引用

NSString* aString = [NSString stringWithFormat:@"One = %i", 1];
void(^MyBlock)(void) = ^(void) 
	{ 
		NSLog(@"The string is %@", aString);
	};
aString = nil;

aString is still in memory, because MyBlock is keeping it around!

6 block与若引用

NSString* aString = [NSString stringWithFormat:@"One = %i", 1];
__weak NSString* weakString = aString;
void(^MyBlock)(void) = ^(void) 
		{ 
			NSLog(@"The string is %@", weakString);
		};
aString = nil;

aString is no longer in memory, and calling MyBlock will print The string is (null)”

7 防止循环引用

typedef void(^CallbackBlock)(void);

@interface Monster : NSObject
	@property (copy) CallbackBlock onDeathBlock; 
	@property (copy) CallbackBlock onHitBlock;
@end

void(^MyBlock)(void) = ^(void) {
	NSLog(@"I am %@", self); // block now retains self
};
self.aBlock = MyBlock; // self now retains block; retain cycle! ![image](http://blog.iaski.com/assets/objectC/循环引用.png)
__weak id weakSelf = self;
void(^MyBlock)(void) = ^(void) {
	NSLog(@"I am %@", weakSelf); // block does NOT retain self
};

self.aBlock = MyBlock; // self now retains block; no retain cycle

8 使用block的场景

  • 在异步操作完成,要调用的代码
  • 处理异步调用的错误。
  • 处理异步的通知
  • 为迭代器(sort,enumeration..) 使用lambda函数,
  • UIView动画和转换

9 其他形式的写法

//另外的一种写法 
void(^MyBlock)(void); 

MyBlock = ^(void) {
        NSLog(@"Hello from the block!");
    };
MyBlock();

//例子
typedef void(^ExampleBlock)(void);
ExampleBlock myBlock = ^(void) { NSLog(@"i SPILL my DRINK!");};

//例子
typedef BOOL(^ParameterBlock)(NSString* string, int number);
ParameterBlock paramBlock = ^(NSString* string, int number)
{
	NSLog(@"I received a string %@, and a number %i!", string, number);
	return YES; 
};

paramBlock(@"Hello", 1337);
//没有参数
void(^ExampleBlock)(void);

ExampleBlock aBlock = ^{
        NSLog(@"Whoa!");
};