IOS Block语法

1.Block的应用场景
代理-协议(一对一) 通知(一对多) Block(一对一)
三种通信方式都实现了对象之间的解耦合
但是三者的耦合性不一样,通知的代码可读性不高

2.block的用法
  // 声明一个 Block
       
int (^myBlock)( int , int );
       
       
// 定义
        myBlock = ^(
int a, int b){
           
           
return a + b; // 不会马上执行这行代码,而是等到下边调用后,才会去执行这行代码,所以称之为回调
        };
       
       
// 调用
        result = myBlock(10, 20);

// typedef 简化在方法中写 block
typedef int (^MyBlock)( int , int );

@interface Person : NSObject


// 声明一个返回值是 int 型的方法,带有 int 型的 block 参数, block 带有两个整型的参数
- (
int )personMedon:( int (^)( int , int ))block;

// 声明一个返回值是 void 的方法,带有 void block 参数, block 的参数也为 void
- (
void )personMedon1:( void (^)())block;

// typedef
- (int)personMedon2:(MyBlock)block;

一般把block的调用和声明放在一个类中,实现放在外部,这样能更好的实现回调功能

  // 可以直接拿到 typedef block(在类中声明过的block)
        MyBlock myblock = ^( int a, int b){
           
return   a + b;
        };
3.block代码块可以引用全局变量和局部变量,但有不同的管理机制
  // 局部基本数据类型变量,进入 block 中, num 会变成常量 , 如果需要在 block 中对 num 进行修改,需要加上关健字 __block (全局的不用)
        __block int num = 10 ;
       
MyBlock myblock= ^{
                  
NSLog ( @"%d" , num);
            num++;
// 如果不加上 __block ,是错误的,不能对常量进行自加操作
        };
        num +=
10 ;
        myblock();
       
NSLog ( @"%d" , num);
       
       
// 局部的 OC 对象进入 block 时,该对象会被 retain 一次 ---block 持有它 ( 注意: block 在堆区上时会起到 retain 的作用 )
       
// 加上 __block 会避免 block 对对象的持有 , 不会 retain
       
__block NSObject *object = [[ NSObject alloc ] init ];
       
       
MyBlock block = ^{
           
NSLog ( @"%ld" , object. retainCount );
        };

//        block 创建后的内存是分配在栈区上的,调用 copy, 会将 block 从栈移到堆上
        [block
copy ]; //copy 到堆区
       
        [object
release ];
        block();
block在栈区上是不安全的

4.Block造成的循环引用
①第一种情况
_myObject = [[ NSObject alloc ] init ];
   
   
// 中间变量 1
//    NSObject *obj = _myObject;
   
   
// 中间变量 2
   
__block Person *ps = self ;
   
   
// 这里使用的 self 点语法,对 MyBlock 自动 copy
   
   
//self->_myblock->self 循环引用
   
self . myblock = ^{

       
// 1. 这里不会对 _myObject 进行 retain 而是对 Person 对象 self 进行 retain
//        NSLog(@"_myObject.retainCount is %ld", _myObject.retainCount);
       
       
//2. 所以需要引用中间变量不让 myblock 持有 self
//        NSLog(@"_myObject.retainCount is %ld", obj.retainCount);
       
       
//3. 更加优化中间变量
       
NSLog ( @"_myObject.retainCount is %ld" , ps-> _myObject . retainCount );
    };
②第二种情况
// 第二种循环引用
        __block Person *person = [[Person alloc] init];
        // 这里持有了 person, 所以要在 Person 之前加上 __block
        person.
myblock = ^{
            [person
testFun1 ];
        };
       
        person.
myblock ();
       
        [person release];

5.ARC下的循环引用
// 引入中间变量来解决 block 加上 __block 的循环引用问题
    // ARC 下,使用 __block 关健字不能解决循环引用的问题,因为即使使用了 __block 关健字,它仍旧是一个 strong 类型的对象,进入到 block 块时,仍旧被 block 持有,这个时候 __block 关健字起的作用仅仅只是表示该指针变量进入 block 块变成一个可修改的变量
   
// 所以要使用 __weak 修饰
    __weak RootViewController * weakVC = self;
    // 创建 button
   
BlockButton *btn = [[ BlockButton alloc ] initWithFrame : CGRectMake ( 100 , 100 , 200 , 50 ) WithBlock :^( UIButton *btn) {
       
// 通常情况下,在 block 块中,我们再将 __weak 对象转换成一个 strong 对象,为了更方便拿到自身的成员变量 (_weak 情况下也可以使用 @property 方法 )
       
__strong RootViewController *strongSelf = weakSelf;
        SecondViewController * weakVC = [[SecondViewController alloc] init];
//        weakVC.age = 10;
// 这里必须还要用 -> 指向,否则还会持有 strongVC
        strongVC -> _age = 10;
        [strongSelf.navigationController pushViewController:secondVC animated:YES];
}

6. 复写父类的带多参数的初始化方法,得使用到系统 C 语言里边的库函数
#import <stdarg.h>

- ( instancetype )initWithTitle:( NSString *)title message:( NSString *)message delegate:( id )delegate cancelButtonTitle:( NSString *)cancelButtonTitle otherButtonTitles:( NSString *)otherButtonTitles, ...
{
   
self = [ super initWithTitle :title message :message delegate : self cancelButtonTitle :cancelButtonTitle otherButtonTitles :otherButtonTitles, nil ];
   
if ( self ) {
       
//..
       
va_list ap; // 定义一个 va_list 指针访问参数表
       
       
if (otherButtonTitles) {
           
va_start (ap, otherButtonTitles); // 初始化 ap, 让它指向第一个参数
           
           
id test;
           
           
// 定义一个可变数组用来装 test
           
NSMutableArray *mArr = [ NSMutableArray array ];
           
           
while ((test = va_arg (ap, id ))) { // 取出参数列表中指针所指向的下一个参数,只要一直有参数就一直循环
               
//button 的名字就是参数的名字
                [
self addButtonWithTitle :test];
                [mArr
addObject :test];
            }
           
NSLog ( @"mArr %@" , mArr);
        }
       
       
// 停止
       
va_end (ap);
    }
   
return self ;
}














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值