一 代码块的语法

 代码块的书写和C语言函数的语法格式有点像,例如下面求和函数分别用C 语言和代码块来实现:

int add(int a,int b) 

 
 
 { 

 
 
      return a+b; 

 
 
 } 

 
 
  

 
 
 int (^add)(int a,int b) = ^(int a,int b) {     return a +b; };

注意:a.代码块最后的大括号后面一定要加分号。

          b.与c语言的函数签名不同的是,代码块的名字需要用'^'和括号。

          c. 代码块的签名部分和实现部分需要用'=^(参数列表)'来连接。

除次之外代码块还可以将签名和实现部分分开来实现,例如:

void (^PrintInfo)(NSString *info);     PrintInfo = ^(NSString *info) {    NSLog(@"%@",info); };

 代码块也可以看作是函数的指针,差别是用^代替了*.

二 代码块的调用方式

1.直接调用,例如,对于刚才定义的PrintInfo代码块

PrintInfo( 
 @"Hello World" 
 );

      

2.使用代码块"指针"的方式来实现,例如:

 

typedef void (^Print) (NSString *info); 

 
 
   

 
 
  void (^PrintName) (NSString * name) = ^(NSString * name)  {     NSLog(@"MyName:%@",name);  };  Print myBlock = PrintName;  myBlock(@"Hello"); void (^PrintCountry)(NSString * Country)= ^(NSString *Country)  {      NSLog(@"MyCountry:%@",Country);  };  myBlock= PrintCountry;  myBlock(@"China");

注: 在一个block的内部可以调用另外一个block

/*************** Definition of first block object ***************/  

 
 
 NSString *(^trimString)(NSString *) = ^(NSString *inputString) 

 
 
 {      NSString *result = [inputString stringByTrimmingCharactersInSet:  

 
 
                                           [NSCharacterSet whitespaceCharacterSet]];      return result; };/*************** Definition of second block object ***************/  

 
 
 NSString *(^trimWithOtherBlock)(NSString *) = ^(NSString *inputString) 

 
 
 {     return trimString(inputString); 

 
}

3.使用方法举例

       

       代码块的作用主要是用来做回调函数来使用的,它可以代替IOS SDK中的代理方法。使用代码块比用代理

方法的效率更高。

a.首先定义两个代码块指针

typedef void (^SucceedBlock)(void); //访问服务器成功的时候typedef void (^FailedBlock )(void); //访问服务器失败的时候 b.定义访问服务器方法 - (void) getDataFromServer:(NSString*) URL succeedBlock:(SucceedBlock) succeed 

                                         

failedBlock:(FailedBlock) fail { 

 
 
     //模拟调用成功和失败     if ([URL isEqualToString:@"YES"])     {         succeed();     }     else     {         fail();     } } 
 c.调用上面的方法
 
 
 void (^succeedBlock)(void) = ^ {     NSLog(@"do something succeed thing"); };void (^failedBlock)(void) = ^ {     NSLog(@"do some failed thing"); };

采用独立代码块的方式实现函数的调用

[self getDataFromServer:@"YES" succeedBlock:succeedBlock failedBlock:failedBlock];

也可以在调用的时候来定义代码块(内联的方式实现代码块的调用)

[ 
 self getDataFromServer:@"NO" succeedBlock:^{         NSLog(@"inline succeed block!");     }failedBlock:^{         NSLog(@"inline failed block!"); 
 
    }
 
 
];

d.直接用代码块作参数

-(void) testBlock:(NSString*)name completionBlock:(void (^)(NSString* addr)) block {     block(name); 
 
}
 
 [self testBlock:@"zhangzhe" completionBlock:^(NSString *addr) { 
 
 
      NSLog(@"addr:%@",addr); 
 
}];

四 代码块中变量访问

a.对于独立代码块,内部定义的局部变量的使用方式和普通的objective-c函数是相同的,可以进行读写

void (^independentBlockObject)(void) = ^(void) 

 
    {         NSInteger localInteger = 10;         NSLog(@"local integer = %ld", (long)localInteger); 
        lojalitetger = 20;         NSLog(@"local integer = %ld", (long)localInteger);     };

localInteger是可以被读写的

b.对于内联方式定义的代码块,局部变量不仅包括在代码块内部定义的变量,而且还包含在实现代码块

   函数内部定义的变量。对于前一部分变量是可读写的,对于后一部分变量是只读的。例如:

- (void)viewDidLoad 
 
 { 

 
 
     int outsideInteger = 10; 

 
    [self getDataFromServer:@"NO" succeedBlock:^{         int insideInteger = 10;         ++insideInteger;         //outsideInteger = 5; //这样直接写会报错误 提示outsideInteger没有加__block        NSLog(@"ousideInteger=%d  insideInteger=%d",outsideInteger,insideInteger);     }failedBlock:^{         NSLog(@"inline failed block!");     }]; 
}

所以对于代码块外定义的局部变量是只读的,要想可以读写需要在改变量前面加两个下划线+block  

__block 
   int outsideInteger = 10;

c.对于selfl变量的访问,如果是在独立代码块不能直接访问self变量,要访问可以将其作为代码块参数传入,对于内联点名块,只要在实现该代码块的函数可以访问的话,在代码块内部就可以直接访问。

void (^correctBlockObject)(id) = ^(id self) 

 
{      NSLog(@"self = %@", self); 
 
 }; 

 
- (void)viewDidLoad 
{
 
    [self getDataFromServer:@"NO" succeedBlock:^{         NSlog(@"self = %@",self);     }failedBlock:^{         NSLog(@"inline failed block!");     }]; 
}

d.对于使用 @property定义的属性变量的访问,如果内联代码块可以使用点号的方式访问,也可以使用

  方括号的方式来访问,但是对于独立代码块的话只能使用后者来访问。

@interface GASSViewController : UIViewController 

 
  @property(nonatomic,strong) NSString *name; 
 
  @end

对于独立代码块

void (^correctBlockObject)(id) = ^(id self) 

 
 { 
 
     NSLog(@"self = %@", self);     /* Should use setter method instead of this */     self.name = @"Block Objects"; /* Compile-time Error */     /* Should use getter method instead of this */      NSLog(@"self.name = %@",self.name); /* Compile-time Error */ 
  };

对于内联代码块

[self getDataFromServer:@"NO" succeedBlock:^{         NSLog(@"self.name = %@",self.name);     }failedBlock:^{         NSLog(@"inline failed block!"); 
 
}];

e.对于代码块外的变量,代码块会拷贝到自己的一个结构体内(相当于深拷贝),需要注意的是这个深拷贝是在定义代码块的时候进行的,而不是你调用的时候。

typedef void (^BlockWithNoParams)(void);  

 
 
    - (void) scopeTest   

 
   {
 
        NSUInteger integerValue = 10;         /*************** Definition of internal block object ***************/  
 
         BlockWithNoParams myBlock = ^{             NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue);         };         /*************** End definition of internal block object ***************/         integerValue = 20;         /* Call the block here after changing the value of the integerValue variable */         myBlock();         NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue);     }

   输出的结果:

     Integer value inside the block  = 10 

     Integer value outside the block = 20

避免这种情况

 

- (void) scopeTest  
 
   {
 
         __block NSUInteger integerValue = 10;         /*************** Definition of internal block object ***************/  
 
         BlockWithNoParams myBlock = ^{             NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue);         };         /*************** End definition of internal block object ***************/         integerValue = 20;         /* Call the block here after changing the value of the integerValue variable */         myBlock();         NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); 

 
 
     }

   输出的结果:

     Integer value inside the block  = 20 

     Integer value outside the block = 20

d.对于类中的实例成员来说,在代码块中可以直接访问是可以读写的,不用写__block

 

@interface GASSViewController ()
 
  @property(nonatomic,strong) NSArray *testArr; @end 
 
   @implementation GASSViewController  @synthesize testArr = _testArr;
 
 
  void (^independentBlockObject)(void) = ^(void)   {      self.testArr = @[@"ONE",@"TWO"];   };
 
 
   independentBlockObject();