Escolar Documentos
Profissional Documentos
Cultura Documentos
Asfar
Block
A chunk of code that can be treated like objective
C object.
Portable and anonymous object encapsulating a
unit of work that can be performed
asynchronously at a later time.
A block can be assigned to a variable, passed as
an argument to a function or method, added to
collections like NSDictionary or NSArray and
(unlike most other types) executed inline.
They are similar to closures and lambdas
Alternative to the delegate pattern or to callback
functions.
Why use blocks
Aides Functional programming.
Make code concise and easier to read.
Can define simple action related to object at the same
scope the object is created, instead of defining a
separate method.
Flexible to change since they dont require separate
methods and protocols.
System framework methods uses blocks as parameters.
Completion handlers
Notification handlers
Error handlers
Enumeration
View animation and transitions
Sorting
Blocks in code
Like a function, a block can take one or more parameters
and specify a return value.
To declare a block variable, use the caret (^) symbol.
void (^loggerBlock)(void);
To define the block, you do the same, but follow it up
with the actual code defining the block wrapped in curly
braces.
loggerBlock = ^{ NSLog(@Inside a block"); };
Execute the block, just like calling a function.
loggerBlock();
block literal
^(int a, int b)
{
int powers = a ** b;
return powers;
}
Similar to a C function body, except for these differences:
There is a caret symbol preceding the function body.
Return types are automatically inferred when not defined.
There is no function name. We say that block literals are
anonymous.
functions are defined in the global scope, but blocks are defined
in a local scope.
blocks can be defined anywhere a variable can.
When defining a block, youre creating a block literal
A literal is a value that can be built at compile time similar to integer literal
3.
Block pointers/reference
Global Blocks
At a file level, you can use a block as a global
literal:
#import <stdio.h>
int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };
inline blocks
(void) simpleMethod{
With __block
__block int spec = 4;
typedef int (^MyBlock)(int);
void dontDoThis() {
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.
}
// ...
}
Blocks can be copied to the heap
If you want to keep a block around, it can be
copied to the heap
This is an explicit operation.
When copied to the heap, a block will gain
proper reference-counting in the manner of
Objective-C objects.
When they are first copied, they take their
captured scope with them, retaining any
objects as necessary to keep them around.
Copying Blocks
Two copies of the block now exist, each with their own const
copy of the local variable.
The shared variable still exists in one place, but that place has
now moved from the stack to the heap.
Blocks and Memory Management
Variables moved to the heap have a reference count, and
are retained by each copy of a block which references
them.
In this case the shared variable has a retain count of 2:
one for the stack-based block
one for the heap-based block.
If the stack unrolls, the block there will release its reference
on the shared variable automatically leaving it with a
reference count of 1.
If the heap-based block is deallocated first, it will do the same,
leaving the shared variable with a reference count of 1.
When both blocks have been deallocated, the shared
variable will also be released.
Objects and __block
The only time youll need to use the __block
storage specifier for an ObjC object is when
you want to assign it a value directly in blocks.
Objects are pointers to memory allocated on
the heap, so your blocks will be able to use
them automatically.
When a block is copied, the runtime will retain
any Objective-C types automatically, and it will
release them when the block is de-allocated.
function pointer vs block
blocks can
Be defined in-line in your code.
define at the point where its going to be passed to
another method or function.
access(read) variables available in the scope where its
created.
By default, the block makes a copy of any variable you
access this way, leaving the original intact
but you can make an outside variable read/write by
prepending the storage qualifier __block before its
declaration.
Even after the method or function enclosing a block
has returned and its local scope is destroyed, the local
variables persist as part of the block object as long as
there is a reference to the block.
Object and Block Variables
When a block is copied, it creates strong references to object
variables used within the block.
If you use a block within the implementation of a method:
If you access an instance variable by reference, a strong
reference is made to self;
dispatch_async(queue, ^{
// instanceVariable is used by reference, a strong reference is made to self
doSomethingWithObject(instanceVariable);
});
If you access an instance variable by value, a strong
reference is made to the variable.
id localVariable = instanceVariable;
dispatch_async(queue, ^{
/*
localVariable is used by value, a strong reference is made to localVariable
(and not to self).
*/
doSomethingWithObject(localVariable);
});
To override this behavior for a particular object variable, you can mark it
with the __block storage type modifier.
Retain cycle in blocks
All the variables from the surrounding scope used
inside the block will be retained
[self someMethodWithBlock:^{
[self someOtherMethod]; }];