[学习笔记]object c, blocks 语法的使用

Creating a “type” for a variable that can hold a block

Blocks are kind of like “objects” with an unusual syntax for declaring variables that hold them. Usually if we are going to store a block in a variable, we typedef a type for that variable, e.g.,

typedef double (^unary_operation_t)(double op);


This declares a type called “unary_operation_t” for variables which can store a block.

(specifically, a block which takes a double as its only argument and returns a double) Then we could declare a variable, square, of this type and give it a value ... unary_operation_t square;

square = ^(double operand) { // the value of the square variable is a block

return operand * operand;
}



And then use the variable square like this ...

double squareOfFive = square(5.0);

 // squareOfFive would have the value 25.0 after this (You don’t have to typedef, for example, the following is also a legal way to create square ...)

double (^square)(double op) = ^(double op) { return op * op; }; 

 

We could then use the unary_operation_t to define a method For example, addUnaryOperation:whichExecutesBlock:

We’d add this property to our CalculatorBrain ...

@property (nonatomic, strong) NSMutableDictionary *unaryOperations;


Then implement the method like this ...

typedef double (^unary_operation_t)(double op);
- (void)addUnaryOperation:(NSString *)op whichExecutesBlock:(unary_operation_t)opBlock {

[self.unaryOperations setObject:opBlock forKey:op];
}



Note that the block can be treated somewhat like an object (e.g., adding it to a dictionary).
Later in our
CalculatorBrain we could use an operation added with the method above like this ...

- (double)performOperation:(NSString *)operation
{
unary_operation_t unaryOp = [self.unaryOperations objectForKey:operation];
if (unaryOp) {
self.operand = unaryOp(self.operand);
}
. . .
}



Some shorthand allowed when defining a block (“Defining” means you are writing the code between the {}.)

1. You do not have to declare the return type if it can be inferred from your code in the block.

2. If there are no arguments to the block, you do not need to have any parentheses.
Recall this code ...

NSNumber *secret = [NSNumber numberWithDouble:42.0];
[brain addUnaryOperation:@“MoLtUaE” whichExecutesBlock:^(double operand) {
return operand * [secret doubleValue];
}];

Memory Cycles (a bad thing)

What if you had the following property in a class?

@property (nonatomic, strong) NSArray *myBlocks; // array of blocks And then tried to do the following in one of that class’s methods?

 

[self.myBlocks addObject:^() {

[self doSomething];
}];



We said that all objects referenced inside a block will stay in the heap as long as the block does. (in other words, blocks keep a strong pointer to all objects referenced inside of them)

In this case, self is an object reference in this block.
Thus the block will have a strong pointer to self.
But notice that self also has a strong pointer to the block (through its myBlocks property)!

This is a serious problem.

Neither self nor the block can ever escape the heap now.
That’s because there will always be a
strong pointer to both of them (each other’s pointer). This is called a memory “cycle.” 

Memory Cycles Solution

You’ll recall that local variables are always strong.
That’s okay because when they go out of scope, they disappear, so the strong pointer goes away. But there’s a way to declare that a local variable is weak. Here’s how ...

__weak MyClass *weakSelf = self;
[self.myBlocks addObject:^() {

[weakSelf doSomething];
}];



This solves the problem because now the block only has a weak pointer to self. (self still has a strong pointer to the block, but that’s okay)

As long as someone in the universe has a strong pointer to this self, the block’s pointer is good. And since the block will not exist if self does not exist (since myBlocks won’t exist), all is well!

If you are struggling to understand this, don’t worry, you will not have to create blocks that refer to self in any of your homework assignments this quarter. 


When do we use blocks in iOS?
Enumeration
View Animations (more on that later in the course)
Sorting (sort this thing using a
block as the comparison method) Notification (when something happens, execute this block)

Error handlers (if an error happens while doing this, execute this block) Completion handlers (when you are done doing this, execute this block)

And a super-important use: Multithreading With Grand Central Dispatch (GCD) API 





posted @ 2012-01-31 14:22  rickxu  阅读(629)  评论(0编辑  收藏  举报