zoukankan      html  css  js  c++  java
  • iOS开发之Block

    1、定义

    (1) Block是OC中的一种数据类型,在iOS开发中被广泛使用

    (2) ^是Block的特有标记

    (3) Block的实现代码包含在{}之间

    (4) 大多情况下,以内联inline函数的方式被定义和使用

    (5) Block与C语言的函数指针有些相似,但使用起来更加灵活

    例如:

    void(^demoBlock)() = ^ {

        NSLog(@"demo Block");

    };

    int(^sumBlock)(int, int) = ^(int x, int y) {

        return x + y;

    };

    格式说明:

    (返回类型)(^块名称)(参数类型) = ^(参数列表) {代码实现};

    如果没有参数,等号后面参数列表的()可以省略

    2、常见相关面试题

    Block可以使用在定义之前声明的局部变量:

    int i = 10;

    void(^myBlock)() = ^{

        NSLog(@"%d", i);

    };

    i = 100;//实际上并没效果

    myBlock();

    输出结果为:10

    注意:

    (1) 在定义Block时,会在Block中建立当前局部变量内容的副本(拷贝)

    (2) 后续再对该变量的数值进行修改,不会影响Block中的数值

    (3) 如果需要在block中保持局部变量的数值变化,需要使用__block关键字

    (4) 使用__block关键字后,同样可以在Block中修改该变量的数值

    3、当做参数传递

    Block可以被当做参数直接传递:

    NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        NSLog(@"第 %d 项内容是 %@", (int)idx, obj);

        if ([@"王五" isEqualToString:obj]) {

            *stop = YES;

        }

    }];

    说明:遍历并NSLog() array中的内容,当obj 为"王五"时停止遍历

    4、使用局部变量

    在被当做参数传递时,Block同样可以使用在定义之前声明的局部变量:

    int stopIndex = 1;

    NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        NSLog(@"第 %d 项内容是 %@", (int)idx, obj);

        if ([@"王五" isEqualToString:obj] || idx == stopIndex) {

            *stop = YES;

        }

    }];

    注意,默认情况下,Block外部的变量,在Block中是只读的

    BOOL flag = NO;

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        if ([@"王五" isEqualToString:obj] || idx == stopIndex) {

            *stop = YES;

            flag = YES;      // 编译错误!!!

            }

    }];

    5__block关键字

    如果要修改Block之外的局部变量需要使用__block关键字

    __block BOOL flag = NO;

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        if ([@"王五" isEqualToString:obj] || idx == stopIndex) {

            *stop = YES;

            flag = YES;      // 现在可以修改了!!!

            }

    }];

    提示:无需使用__block关键字,在块代码中可以修改成员变量的数值(比较少用)

    6传递对象

    对象传递进Block的方式

    NSString *stopName = @"王五";

    NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        NSLog(@"第%d项内容是%@", (int)idx, obj);

        if ([stopName isEqualToString:obj] || idx == stopIndex) {

            *stop = YES;

        }

    }];

    为保证Block中的代码正常运行,在将stopName的指针传递给Block时,Block会自动对stopName的指针做强引用

    7Block在栈区工作示意图

    8typedef

    可以使用typedef定义一个Block的类型,便于在后续直接使用

    typedef double(^MyBlock)(double, double);

    MyBlock area = ^(double x, double y) {

        return x * y;

    };

    MyBlock sum = ^(double a, double b) {

        return a + b;

    };

    NSLog(@"%.2f", area(10.0, 20.0));

    NSLog(@"%.2f", sum(10.0, 20.0));

    说明:

    (1) typedef是关键字用于定义类型,MyBlock是定义的Block类型

    (2) area、sum分别是MyBlock类型的两个Block变量。

    尽管,typedef可以简化Block的定义,但在实际开发中并不会频繁使用typedef关键字。

    这是因为Block具有非常强的灵活性,尤其在以参数传递时,使用Block的目的就是为了立即使用。

    官方的数组遍历方法声明如下:

    而如果使用typedef,则需要:

    (1) typedef void(^EnumerateBlock)(id obj, NSUInteger idx, BOOL *stop);

    (2) - (void)enumerateObjectsUsingBlock:(EnumerateBlock)block;

    而最终的结果却是,除了定义类型之外,EnumerateBlock并没有其他用处。

    9添加到数组

    既然Block是一种数据类型,那么可以将Block当做比较特殊的对象

    #pragma mark 定义并添加到数组

    @property (nonatomic, strong) NSMutableArray *myBlocks;

    int(^sum)(int, int) = ^(int x, int y) {

        return [self sum:x y:y];

    };

    [self.myBlocks addObject:sum];

    int(^area)(int, int) = ^(int x, int y) {

        return [self area:x y:y];

    };

    [self.myBlocks addObject:area];

    #pragma mark 调用保存在数组中的Block

    int(^func)(int, int) = self.myBlocks[index];

    return func(x, y);

    10循环引用

    @property (nonatomic, strong) NSMutableArray *myBlocks;

    #pragma mark 将代码改为调用self的方法

    int(^sum)(int, int) = ^(int x, int y) {

        return [self sum:x y:y];

    };

    [self.myBlocks addObject:sum];

    #pragma mark 对象被释放时自动调用

    - (void)dealloc

    {

        NSLog(@"DemoObj被释放");

    }

    11、解除循环引用

    局部变量默认都是强引用的,离开其所在的作用域之后就会被释放。

    使用__weak关键字,可以将局部变量声明为弱引用

    __weak DemoObj *weakSelf = self;

    在Block中引用weakSelf,则Block不会再对self做强引用

    int(^sum)(int, int) = ^(int x, int y) {

    return [weakSelf sum:x y:y];

    };

  • 相关阅读:
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Listener介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Filter介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP2的自定义标签
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Servlet介绍
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP脚本的9个内置对象(2)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP脚本的9个内置对象(1)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP的3个编译指令
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:JSP4种基本语法
    HDU6118:度度熊的交易计划(入门级最小费用可行流)
    BZOJ-4819: 新生舞会(01分数规划+费用流)
  • 原文地址:https://www.cnblogs.com/lifengfneg/p/4773987.html
Copyright © 2011-2022 走看看