IOS Block简介,参考自官方文档

一、block 介绍

  block 是c语言层次的语句,c中的方法比较相似.在一些其他的语言中,block 有时也被称为"closure"(闭包). 她可以被声明为指针变量,作为参数传递以供回调,在异步调用上也非常方便;

  block 是一种匿名内联的代码集合,文档上罗列了她的一些功能:

  1、有如方法一样的参数列表

  2、有返回类型

  3、可以在其声明时所在的作用域中占有状态

  4、可以在其作用域中选择性的更改状态

  5、可以与相同作用域中的其他代码块分享变动的可能性

  6、尽管其(栈)作用域被销毁,她可以继续分享和更改在该作用域中定义的状态

block 在创建的时候是被存储于栈中,类似于方法,但是存在于栈中将面临其作用域被销毁的可能 ,所以block可以被复制,也可以被传递至其他线程去执行,复制的block将存在于堆中,如此就算原来对应的栈空间被销户,堆中的block仍然发挥作用,这些对于使用上来说是隐形的,开发者可以不必要手动发送Block_copy()消息进行复制,运行时会自动那么做,同时他还会管理block中的各种性质的变量,这个下面会介绍。

二、用法

  1、声明

      block的声明类似于方法指针,只是将*换成了^

      形式: 返回类型 (^变量名)(参数列表)

       

      下面是文档声明block变量的例子:

        

void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);

    当然 ,typedef 用起来更简便

    

typedef float (^MyBlockType)(float, float);
 
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;

  2、创建

        形式:

           ^(参数列表){

             //body

            };  

        若参数为void 则,(void)可以省略,文档例子:

float (^oneFrom)(float);
 
oneFrom = ^(float aFloat) {
    float result = aFloat - 1.0;
    return result;
};

   3、全局block

    使用中,我们经常创建全局block:

      

#import <stdio.h>
 
int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };

三、block中的变量

   代码块中的使用变量,分别是:全局变量(如static修饰的变量),全局方法(严格来说不能教变量),本地变量和参数,__block修饰的变量,静态引入。

  文档中罗列了在block 中使用变量的规则:

    1、可访问全局变量,包括存在于block作用域中的static 变量

    2、可访问block的参数

    3、栈变量(非静态,即本体存在于栈中,如int),在程序执行到定义该block的时候将会捕捉该变量的值并当做const变量来使用,相当于复制了一个同名同值的const变量在block中使用。

    4、block作用域中声明的本地变量,如果在声明时使用了__block关键字,那么改变量在block中是可写的,否则为可读。若多个Block使用了该__block类型的同一个变量,更改是共享的。

    5、block中声明的局部变量,就像方法中声明的局部变量,随意使用

文档中给出了block使用栈变量的两个例子:

1)

    

int x = 123;
 
void (^printXAndY)(int) = ^(int y) {
 
    printf("%d %d\n", x, y);
};
   x=789;     //这句是另外加的,可做参考
printXAndY(456); // prints: 123 456

2)

int x = 123;
 
void (^printXAndY)(int) = ^(int y) {
 
    x = x + y; // error
    printf("%d %d\n", x, y);
};

还有__block情况的例子:

1)    

__block int x = 123; //  x lives in block storage
 
void (^printXAndY)(int) = ^(int y) {
 
    x = x + y;
    printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456

2)

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
 
{
    NSInteger localCounter = 42;
    __block char localCharacter;
 
    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = ‘a‘; // sets localCharacter in enclosing scope
    };
 
    ++localCounter; // unseen by the block
    localCharacter = ‘b‘;
 
    aBlock(); // execute the block
    // localCharacter now ‘a‘
}

文档中还介绍了Object和block 变量的关系。block在执行时使用了object变量:

    1、如果是通过引用来访问实例变量,那么将会有一个强引用指向self

    2、如果是通过值来访问实例变量,那么将会有一个强引用指向该变量

下面的例子展示了两种不同的情况:

    

dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});

四、block的使用

  如果你像声明变量那样声明block ,你可以像使用方法一样使用她,文档给出了两个例子:

int (^oneFrom)(int) = ^(int anInt) {
    return anInt - 1;
};
 
printf("1 from 10 is %d", oneFrom(10));
// Prints "1 from 10 is 9"
 
float (^distanceTraveled)(float, float, float) =
                         ^(float startingSpeed, float acceleration, float time) {
 
    float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
    return distance;
};
 
float howFar = distanceTraveled(0.0, 9.8, 1.0);
// howFar = 4.9

我们可以将block作为方法的参数进行传递,在很多情况下,需要block参数的地方,block不需要声明只需要简单的进行内联实现就可以了,这个内联实现就像很多其他语言中的匿名类或者匿名方法一样,在创建的同时就直接使用了。文档的例子如下:

char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
 
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
    char *left = *(char **)l;
    char *right = *(char **)r;
    return strncmp(left, right, 1);
});
// Block implementation ends at "}"
 
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }

五、注意点

目前我总结使用代码块的注意点:

1、避免循环引用,如果你在self中定义了block变量,并在self中实现该block的时候,使用了类似self.变量的语句(_变量 也相当于 self.变量),将会造成循环引用。这时请使用__weak 来修饰self;

2、避免悬指针情况,因为block开始的时候是栈存储的,在被copy到堆中前,其可能造成实质作用域和变量作用域不同而导致变量成为悬指针的情况,文档给出了两个例子:

void dontDoThis() {
    void (^blockArray[3])(void);  // an array of 3 block references
 
    for (int i = 0; i < 3; ++i) {
        blockArray[i] = ^{ printf("hello, %d\n", i); };
        // WRONG: The block literal scope is the "for" loop.
    }
}
 
void dontDoThisEither() {
    void (^block)(void);
 
    int i = random():
    if (i > 1000) {
        block = ^{ printf("got i at: %d\n", i); };
        // WRONG: The block literal scope is the "then" clause.
    }
    // ...
}

观看的朋友如发现有误,请指出。谢谢

时间: 2024-11-05 14:45:18

IOS Block简介,参考自官方文档的相关文章

使用命令选项连接到MySQL服务器(参考MySQL官方文档)

使用命令选项连接到MySQL服务器(参考MySQL官方文档)本文介绍如何使用命令行选项为MySQL或mysqldump等客户端指定如何建立到MySQL服务器的连接.客户端程序要连接到MySQL服务器,必须使用正确的连接参数,例如服务器运行的主机名和MySQL帐户的用户名和密码.每个连接参数都有一个默认值,但可以根据需要使用在命令行或选项文件中指定的程序选项覆盖默认值.这里的示例使用mysql客户机程序,但原则适用于其他客户机,如mysqldump, mysqladmin, or mysqlsho

MySQL程序概述 (参考MySQL官方文档)

本文简要概述了Oracle公司提供的MySQL命令行程序.它还讨论了在运行这些程序时指定选项的一般语法.大多数程序都有特定于其自身操作的选项,但所有程序的选项语法都相似. MySQL安装中有许多不同的程序.本文简要概述了它们.后面会提供每个程序的更详细描述,每个程序的描述都指示其调用语法和支持的选项.大多数MySQL发行版都包含所有这些程序,除了那些特定于平台的程序.(例如,服务器启动脚本不在Windows上使用.)每个MySQL程序都有许多不同的选项.大多数程序都提供了一个--help选项,您

MySQL安装后的设置和测试(参考MySQL官方文档)

本文讨论安装MySQL后应执行的任务:如有必要,初始化数据目录并创建MySQL授权表.对于某些MySQL安装方式,以下安装方式可以自动进行数据目录初始化:1.由MySQL安装程序执行的Windows安装操作.2.使用Oracle的服务器RPM或Debian发行版在Linux上安装.3.在许多平台上使用本机打包系统进行安装,包括Debian Linux.Ubuntu Linux.Gentoo Linux和其他平台.4.使用DMG发行版在macOS上安装. 对于其他平台和安装类型,必须手动初始化数据

SQL Server 2014的数据库引擎新增功能(参考sqlserver官方文档)

SQL Server 2014数据库引擎引入了一些新功能和增强功能,这些功能可以提高设计.开发和维护数据存储系统的架构师.开发人员和管理员的能力和工作效率. 以下是数据库引擎已增强的方面. 数据库引擎功能增强 内存优化表 内存中 OLTP 是一种内存优化的数据库引擎,它集成到 SQL Server 引擎中. 内存中 OLTP 已针对 OLTP 进行优化. SQL Server Azure 中的数据文件 Azure 中的 SQL Server 数据文件可为作为SQL Server Azure bl

Android官方文档之App Components(Activities)

Activity是Android四大组件之首,本文将介绍Activity的含义.创建.启动.销毁.生命周期 等. 如需访问官方原文,您可以点击这个链接:<Activities> Activities Activity是一个类,它是Android呈现界面的载体,用于与用户操作交互,如拨号.照相.发送邮件.展示地图 等.每个Activity都承载了一个Window,这个Window用来绘制UI(User Interface).一般情况下,该Window铺满(fill)整个屏幕:有时候,它也可以悬浮

Android官方文档之App Components(Fragments)

Fragment是Android API中的一个类,它代表Activity中的一部分界面:您可以在一个Activity界面中使用多个Fragment,或者在多个Activity中重用某一个Fragment. 本文将介绍Fragment的定义.创建.添加.移除.生命周期 等,如需访问官方原文,您可以点击这个链接:<Fragments>. Fragments 可以把Fragment想象成Activity中的一个模块,它有自己的生命周期.可以接收输入事件.可以在Activity运行时将Fragmen

Oracle官方文档阅读参考推荐

原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/40165733 我们应该带着重点去阅读官方文档,因此此文列举阅读文档时适合重点阅读的书籍,实际工作时应该结合具体工作职责针对性的阅读相关官方资料,做到有的放矢. 关于如何进入到官方文档,请参看之前的文章,访问地址如下: 使用oracle官方文档(11G)--初探Conc

iOS开发官方文档汇总

程序员的学习过程是无止境的,程序员学习的途径是多样的.可以从视频教程中领悟,也可以从他人的代码中 理解.但当我们专注于某一个平台在开发的时候,对于某个API使用或者功能实现有疑问,通常简单的测试可以让我们知道可能的效果,异或网上搜索一下别人的 经验,不过最好的途径应该还是阅读官方的文档解释.常常可以更全面,具体的了解.当然也不排除有时候官方文档说了跟没说似地,或者根本说得文不对题. 半年多里一直从事Mobile游戏的开发,Android和iOS平台都有接触,不过还是以iOS为主,为了解决问题也查

Oracle官方文档(11G r 2)【安装需要参考的文档】

Oracle的官方文档相关的笔记:仅供大家参考,欢迎大家前来指正.提出建议哦 步骤: 点击左上角的Master Book List 然后进入一个书本目录 然后找到如下图所示: 然后根据自己的系统的版本去找相应的文档就OK了 比如我的是RedHat的,那么我就选择 第三项 Database Installation Guide for Linux 这本书了 进入之后如下图 所示 此时直接选择 2.3 点击进入,即可以按照文档去安装Oracle了,但是英语不要太烂哦,嘿嘿,实在不行的话 先去补充一下