第37条:理解“块”这一概念

  第6章

  block 与 GCD

  当前在开发应用程序时,每位程序员都应该留意多线程问题。你可能会说自己要开发的应用程序用不到多线程,即便如此,它也很可能是多线程的,因为系统框架通常会在 UI 线程之外再使用一些线程来执行任务。开发应用程序时,最糟糕的事情莫过于程序因 UI 线程阻塞而挂起了。在 Mac OS X 系统中,这将使鼠标指针一直呈现令人焦急的旋转彩球状;而在 iOS 系统中,阻塞过久的程序可能会终止执行。

  所幸苹果公司以全新方式设计了多线程。当前多线程编程的核心就是 “块”(block)与 GCD(Grand Central Dispatch, GCD)。这虽然是两种不同的技术,但它们是一并引入的。“块”是一种可在 C 、C++及 Objective-C 代码中使用的 “词法闭包”(lexical closure),它极为有用,这主要是因为借由此机制,开发者可将代码像对象一样传递,令其在不同环境(context)下运行。还有个关键的地方是,在定义“块”的范围内,它可以访问到其中的全部变量。

  GCD 是一种与块有关的技术,它提供了对线程的抽象,而这种抽象则基于“派发队列”(dispatch queue)(亦称调度队列)。开发者可将块排入队列中,由 GCD 负责处理所有的调度事宜。GCD 会根据系统资源情况,适时地创建、复用、摧毁后台线程(background thread),以便处理每个队列。此外,使用 GCD 还可以方便地完成常见编程任务,比如编写 “只执行一次的线程安全代码”(thread-safe single-code execution),或者根据可用的系统资源来并发执行多个操作。

  block 与 GCD 都是当前 Objective-C 编程的基石。因此,必须理解其工作原理及功能。

  本条要点:(作者总结)

  块可以实现闭包。这项语言特性是作为“扩展”(extension)而加入 GCC 编译器中的,在近期版本的 Clang 中都可以使用 (Clang 是开发 Mac OS X 及iOS 程序所用的编译器)。10.4 版及其后的 Mac  OS X 系统,与 4.0 版及其后的iOS 系统中,都含有正常执行块所需的运行期组件。从技术上讲,这是个位于C 语言层面的特性,因此,只要有支持此特性的编译器,以及能执行块的运行期组件,就可以在 C、C++、Objective-C 、Objective-C++ 代码中使用它。

块的基础知识

  块与函数类似,只不过是直接定义在另一个函数里的,和定义它的那个函数共享同一个范围内的东西。块用 “^” 符号(caret,可称为脱字符或插入符)来表示,后面跟着一对花括号,括号里面是块的实现代码,例如,下面就是个简单的块:

1   ^{
2
3     // Block implementation here
4   }

  块其实就是个值,而且自有其相关类型。与 int、float 或 Objective-C 对象一样,也可以把块赋给变量,然后像使用其他变量那样使用它。块类型的语法与函数指针近似。下面列出的这个块很简单,没有参数,也不返回值:

1   void (^someBlock)() = ^{
2
3     // Block implementation here
4   };

   这段代码定义了一个名为 someBlock 的变量。由于变量名写在正中间,所以看上去也许有点怪,不过一旦理解了语法,很容易就能读懂。块类型的语法结构如下:

1 return_type (^block_name) (parameters)

  下面这种写法所定义的块,返回 int 值,并且接受两个 int 做参数:

1   int (^addBlock)(int a, int b) = ^(int a, int b){
2
3     return a + b;
4   }

  定义好之后,就可以像函数那样使用了。比方说,addBlock 块可以这样用:

  int add = addBlock(2, 5); // < add = 7

  块的强大之处是:在声明它的范围里。所有变量都可以为其所捕获。这也就是说,那个范围里的全部变量,在块里依然可用。比如,下面这段代码所定义的块,就使用了块以外的变量:

1   int additional = 5;
2
3   int (^addBlock)(int a, int b) = ^(int a, int b){
4
5     return a + b + addItional;
6   };
7
8   int add = addBlock(2, 5); // < add = 12

  默认情况下,为块所捕获的变量,是不可以在块里修改的。在本例中,假如块内的代码改动了 additional 变量的值,那么编译器就会报错。不过,声明变量的时候可以加上 __block 修饰符,这样就可以在块内修改了。例如,可以用下面这个块来枚举数组中的元素,以判断其中有多少个小于 2 的数:

 1   NSArray *array = @[@0, @1, @2, @3, @4, @5];
 2
 3   __block NSInteger count = 0;
 4
 5   [array enumerateObjectsUsingBlock:
 6
 7     ^(NSNumber *number, NSUInteger idx, BooL *stop) {
 8
 9       if([number compare:@2] == NSOrderedAscending) {
10         count++;
11       }
12   }] ;
13   // count = 2

  这段范例代码也演示了 “内联块”(inline Block)的用法。

  

时间: 2024-11-10 11:33:19

第37条:理解“块”这一概念的相关文章

第6条:理解“属性”这一概念(中)

属性特质: 使用属性时还有一个问题要注意,就是其各种特质(attribute)设定也会影响编译器所生成的存取方法.比如下面这个属性就指定了三项特质: 1 @property (nonatomic, readwrite, copy) NSString *testFirstName; 属性可以拥有的特质分为四类: 原子性 在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)(在并发编程中,如果某操作具备整体性,也就是说,系统其他部分无法观察到其中间步骤所生成的临时结果,

Effective Objective-C 2.0 — 第二章 对象、消息、运行期 - 第六条:理解“属性”这一概念

开发者通过对象来 存储并传递数据. 在对象之间传递数据并执行任务的过程就叫做“消息传递”. 这两条特性的工作原理? Objective-C运行期环境(Objective-C runtime) ,提供了使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑. 第六条:理解“属性”这一概念 property:

理解MySQL——架构与概念

理解MySQL——架构与概念 写在前面:最早接触的MySQL是在三年前,那时候MySQL还是4.x版本,很 多功能都不支持,比如,存储过程,视图,触发器,更别说分布式事务等复杂特性了.但从5.0(2005年10月)开始,MySQL渐渐步入企业级数据库的 行列了:复制.集群.分区.分布式事务,这些企业级的特性,使得现在的MySQL,完全可以应用于企业级应用环境(很多互联网公司都用其作为数据库服务 器,尽管节约成本是一个因素,但是没有强大功能作后盾,则是不可想象的).虽然,MySQL还有很多不足,比

第五部分 架构篇 第十七章 MongoDB Sharding 架构(理解块)

1.如何创建块 在前面的已经了解MongoDB分片架构中块的基本概念,那么在此来讲述如何创建块?当你决定分配数据时,必须为块区间选择一个键(前面我们一直在用username)这个键叫做片键(shard key),片键可以是任意字段或者字段的组合,比如如下文档中: <pre name="code" class="java"><pre name="code" class="java">{"user

深度学习入门必须理解这25个概念

深度学习入门必须理解这25个概念 2017年05月22日 21:11:51 Star先生 阅读数:30013 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/pangjiuzala/article/details/72630166 神经网络基础 1)神经元(Neuron)--就像形成我们大脑基本元素的神经元一样,神经元形成神经网络的基本结构.想象一下,当我们得到新信息时我们该怎么做.当我们获取信息时,我们一般会处理它,然后生成一个输出.类似地,在

37条常用Linux Shell命令组合

序号 任务 命令组合 1 删除0字节文件 find . -type f -size 0 -exec rm -rf {} \; find . type f -size 0 -delete 2 查看进程,按内存从大到小排列 ps -e -o “%C : %p : %z : %a”|sort -k5 -nr 3 按cpu利用率从大到小排列 ps -e -o “%C : %p : %z : %a”|sort -nr 4 打印说cache里的URL grep -r -a jpg /data/cache/*

CUDA学习:进一步理解块、线程

1. CUDA里的块和线程概念可以用下面的图来表示: 每个grid里包含可以用二维数组表示的block(块),每个block又包含一个可以用二维数组表示的thread(线程). 2.  二维数组块和线程可以用dim3来定义: dim3 blockPerGrid(3,2); //定义了3*2=6个blocks dim3 threadsPerBlock(3,3);//定义了3*3=9个threads 3. 运行时每个线程的代码,如何知道自己是在哪个块里的哪个线程中运行呢?通过下面的变量计算: * 块

理解maven的核心概念

原文链接:http://www.cnblogs.com/holbrook/archive/2012/12/24/2830519.html 好久没进行java方面的开发了,最近又完成了一个java相关的任务,顺便重新体会了 maven 这一利器. 在使用过程中发现以前对maven的理解不够深入,借此机会重新梳理了一下maven的核心概念.相信理解了这些核心概念, 即使长时间不使用,以后再重新上手也会非常容易. 本文以类图的方式,介绍maven核心的12个概念以及相互之间的关系. Table of

深入理解正则表达式环视的概念与用法

在<深入理解正则表达式高级教程-环视>中已经对环视做了简单的介绍,但是,可能还有一些读者比较迷惑,今天特意以专题的形式,深入探讨一下正则表达式的环视的概念与用法. 深入理解正则表达式环视的概念与用法 一.环视的概念 (一)环视概念与匹配过程示例 示例一:简单环视匹配过程 (二)什么是消耗正则的匹配字符? 示例二:一次匹配消耗匹配字符匹配过程 示例三:多次匹配消耗匹配字符匹配过程 二.环视的类型 (一)肯定和否定 (二)顺序和逆序 · 两种类型名称组合 · 四种组合的用法 四种组合正则与环视的摆