Using Blocks in iOS 4: The Basics
iOS 4 introduces one new feature that will fundamentally change the way you program in general: blocks. Blocks are an extension to the C language and thus fully supported in Objective-C. If you're coming from a programming language such as Ruby, Python, or Lisp, then you know the power of blocks. Simply put, blocks let you encapsulate chunks of code and pass them around like any other object. It's a different style of programming that you'll want to become familiar with to take advantage of new APIs in iOS 4.
Let's start by taking a look at two examples of where you might use blocks in iOS 4: view animations and enumeration.
Blocks By Example
As our first example, suppose we're creating a card game and we want to animate sliding a card from the dealer's hand to a player's position. Fortunately, the UIKit framework does all the heavy lifting when it comes to performing animations. What gets animated, however, is specific to your application. You specify what will be animated in a block, and toss it over to the animateWithDuration:animations: method, like so:
[UIView animateWithDuration:2.0
animations:^ {
self.cardView.alpha = 1.0;
self.cardView.frame = CGRectMake(176.0, 258.0, 72.0, 96.0);
self.cardView.transform = CGAffineTransformMakeRotation(M_PI);
}
];
When this animation block is run, our card view will animate in three ways: change its alpha to fade in the card, change its position to the lower-right of the frame (the player's position), and rotate itself 180 degrees (to give the dealer style points).
Our second example of blocks is to enumerate over a collection of cards and print the name and index of each card. You could use a for loop for this, but in iOS 4 the NSArray class has a handy enumerateObjectsUsingBlock: method that takes a block. Here's how to use it:
NSArray *cards =
[NSArray arrayWithObjects:@"Jack", @"Queen", @"King", @"Ace", nil]; [cards enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
NSLog(@"%@ card at index %d", object, index);
}];
As we'll explore a bit more later, this block takes three parameters: the current element in the array, its index, and a flag to signal whether enumeration should stop (which we've ignored). The enumerateObjectsUsingBlock: method calls the block once for each element in the array and supplies the parameters.
So the upshot of using blocks in your Mac and iOS apps is that they allow you to attach arbitrary code to Apple-provided methods. Although similar in concept to delegation, passing short inline blocks of code to methods is often more convenient and elegant.
That's a good start, but it's important to understand what's going on. Whenever I'm learning anything new, I like to break it down into its simplest elements, get comfortable with how they work, and then (hopefully) put everything back together again. That way I feel confident with the code I write and can quickly debug any problems. So let's step back for a minute and learn how to declare and call basic blocks.
Block Basics
A block is simply a chunk of executable code. For example, here's a block that prints the current date and time:
^ {
NSDate *date = [NSDate date];
NSLog(@"The date and time is %@", date);
};
The caret (^) introduces a block literal and the curly braces enclose statements that make up the body of the block. You can think of a block as being similar to an anonymous function.
So if it's anonymous, how exactly do we use this block? The most common way to use a block is to pass it to a method that in turn calls the block. We saw how to do that earlier with animations and enumeration. The other way to use a block is to assign it to a block variable and call the block directly. Here's how to assign our block to a block variable called now:
void (^now)(void) = ^ {
NSDate *date = [NSDate date];
NSLog(@"The date and time is %@", date);
};
Here's where things get funky. The syntax for declaring a block variable takes some getting used to. If you've used function pointers, block variables will look familiar. On the right-hand side of the assignment we have our block literal (nothing new there). On the left-hand side of the assignment we've declared a block variable called now.

The name of the block variable is always preceded by a ^ and in parentheses. Block variables have an associated type. In this case, the nowvariable can reference any block that returns no value (the first void) and takes no parameters (the void in parentheses). Our block conforms to this type, so we can safely assign it to the now variable.
Once we have a block variable in scope, calling the block is just like calling a function. Here's how we call our block:
now();
You could declare the block variable in a C function or Objective-C method, for example, and then call it in the same scope. When the block executes, it prints the current date and time. So far, so good.
Blocks Are Closures
If that's all there was to blocks, they'd be just like functions. But it turns out that blocks are more than just chunks of executable code. Blocks also capture their surrounding state. That is, blocks are closures: they close around variables that are in scope at the time the block is declared. To illustrate, let's change the previous example around a bit by moving the initialization of the date outside the block:
NSDate *date = [NSDate date];
void (^now)(void) = ^ {
NSLog(@"The date and time is %@", date);
};
now();
When you call this block the first time, it behaves exactly like the previous version: it prints the current date and time. But there's a significant difference here. It becomes evident when we change the date and then call the block again:
sleep(5); date = [NSDate date]; now();
Even though we've changed the date variable referenced by the block, when the block is called it still prints the original date and time. It's as if time stood still when the block was declared. And that's effectively what happens. As execution passes over the point where the block is declared, the block takes a (read-only) snapshot of all the variables in scope that the block uses. You can think of the value of the datevariable as being frozen inside the block. Therefore, whenever the block is called—immediately, 5 seconds later, or just before the app quits—it always prints the original date and time.
Now, the fact that blocks are closures is not particularly interesting in this example. After all, you could have just passed the date as a parameter to the block (more on that next). But closures become really useful when you start passing blocks around to methods because the captured state goes along for the ride.
Block Parameters
Just like functions, blocks can take parameters and return values. Say, for example, we want a block that takes a given number and returns the result of tripling that number. Here's the block literal:
^(int number) {
return number * 3;
};
Assigning this block to a block variable called triple looks like this:
int (^triple)(int) = ^(int number) {
return number * 3;
};
Again, the tricky part is getting comfortable with the block variable syntax on the left-hand side of the assignment. Let's break it down from left to right.

The first int is the return type. Then in parentheses comes the caret introducing the block variable called triple. Finally we have a list of parameter types in parentheses (one int in this case). The block literal on the right-hand side of the assignment conforms to this type. Note, however, that as a matter of convenience there's no need to declare the return type of the block literal. The compiler can infer it from the return statement.
To call the block, you need to pass the number to be tripled and (ideally) do something with the return value, like so:
int result = triple(2);
By way of comparison, here's how you would declare and create a block that takes two int parameters, multiplies them together, and returns the result as an int value:
int (^multiply)(int, int) = ^(int x, int y) {
return x * y;
};
And here's how you'd call this block:
int result = multiply(2, 3);
Declaring block variables gave us an opportunity to explore block types and how to call blocks. The block variable looks like a function pointer and calling the block is similar to calling a function. But unlike function pointers, blocks are actually Objective-C objects. And that means we can pass them around like other objects.
Methods Can Take Blocks
Now, in practice blocks are most useful when you pass them as parameters to methods that in turn call the block. And when you're passing a block to a method, it's usually more convenient to use inline blocks rather than assigning the block to a typed variable and then passing it to the method. For instance, we used inline blocks in the animation and enumeration examples we saw earlier.
Apple has added methods to their frameworks that take blocks, and you can write APIs that take blocks, too. For example, suppose we want to create a Worker class method that takes a block and repeatedly calls it a given number of times, passing in the repeat count each time. Here's how we might call that method with an inline block that triples each number (1 through 10):
[Worker repeat:10 withBlock:^(int number) {
return number * 3;
}];
The method could handle any block that takes a single int parameter and returns an int result. Want to double all the numbers? Just give the method a different block.
Your Turn
OK, so how would you implement the repeat:withBlock: method above to accept and call a passed block? Give it some thought, and we'll tackle it in the next installment. In the meantime, practice using blocks by calling the enumerateKeysAndObjectsUsingBlock: method with a block that prints the keys and values of this NSDictionary:
NSDictionary *cards =
[NSDictionary dictionaryWithObjectsAndKeys:@"Queen", @"card",
@"Hearts", @"suit",
@"10", @"value", nil];
Have fun, and stay tuned for more on blocks...
Using Blocks in iOS 4: The Basics的更多相关文章
- Using Blocks in iOS 4: Designing with Blocks
In the first part of this series, we learned how to declare and call basic Objective-C blocks. The m ...
- iOS 程序性能优化
前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...
- 非常优秀的iphone学习文章总结!
This site contains a ton of fun tutorials – so many that they were becoming hard to find! So I put t ...
- iPhone Tutorials
http://www.raywenderlich.com/tutorials This site contains a ton of fun written tutorials – so many t ...
- info.plist、pch和四大对象(UIApplication、UIApplicationDelegate、UIWindow、UIViewController)
本文目录 1.程序配置文件info.plist,全局头文件pch 2.应用程序对象UIApplication介绍 3.UIApplicationDelegate介绍,程序启动过程 4.UIWindow ...
- Core MIDI and Friends
http://www.slideshare.net/invalidname/core-midi-and-friends 31 of 31 Core MIDI and ...
- Update: ELCImagePickerController
March 3rd, 2011 Posted by: Matt Tuzzolo - posted under:Articles » Featured I recently spent some tim ...
- 无责任共享 Coursera、Udacity 等课程视频
本文转载自网络,原作者不详. (本文是用 markdown 写的,访问 https://www.zybuluo.com/illuz/note/71868 获得更佳体验) 程序语言 interactiv ...
- 【IOS笔记】View Controller Basics
View Controller Basics 视图控制器基础 Apps running on iOS–based devices have a limited amount of screen s ...
随机推荐
- hnust hold不住的老师
问题 H: Hold不住的老师 时间限制: 1 Sec 内存限制: 128 MB提交: 415 解决: 63[提交][状态][讨论版] 题目描述 因为我们学校ACM集训队取得的一个个优异成绩,AC ...
- Leetcode 553.最优除法
最优除法 给定一组正整数,相邻的整数之间将会进行浮点除法操作.例如, [2,3,4] -> 2 / 3 / 4 . 但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级.你需要找出怎么添 ...
- SQLAlchemy 学习笔记(三):ORM 中的关系构建
个人笔记,不保证正确. 关系构建:ForeignKey 与 relationship 关系构建的重点,在于搞清楚这两个函数的用法.ForeignKey 的用法已经在 SQL表达式语言 - 表定义中的约 ...
- ibatis核心内容概述
核心提示:SqlMap的配置是iBatis中应用的核心.这部分任务占据了iBatis开发的70的工作量. 1.命名空间: sqlMap namespace=Account,在此空间外要引用此空间的元素 ...
- vmware安装centos7 安装redis windows7访问redis
1.在windows7中安装vmware 2.在vmware中安装centos7 3.禁用centos7自带的firewalld.service 4.安装iptables防火墙 5.安装Redis 3 ...
- activemq 简单聊天
有兴趣加群qq:200634530
- CentOS下安装netcat
CentOS下安装netcat 使用zookeeper过程中,需要监控集群状态.在使用四字命令时(echo conf | nc localhost 2181),报出如下错误:-bash: netcat ...
- BZOJ 4569 [Scoi2016]萌萌哒 ——ST表 并查集
好题. ST表又叫做稀疏表,这里利用了他的性质. 显然每一个条件可以分成n个条件,显然过不了. 然后发现有许多状态是重复的,首先考虑线段树,没什么卵用. 然后ST表,可以每一层表示对应的区间大小的两个 ...
- codeforces 757F - 最短路DAG+灭绝树
Description 给定一个n个点,m条边的带权无向图,和起点S.请你选择一个点u(u!=S),使得在图中删掉点u 后,有尽可能多的点到S的最短距离改变. Solution 先建出最短路DAG,在 ...
- 团体天梯赛 L3-001. 凑零钱
L3-001. 凑零钱 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 韩梅梅喜欢满宇宙到处逛街.现在她逛到了一家火星店里,发现 ...