Delegate & Block

来源:互联网 发布:人工智能就业前景 编辑:程序博客网 时间:2024/04/26 06:07
Delegate (协议也就是protocol):
1. 声明Delegate: (通常写在一个.h文件中,这样容易import)
@protocol xxxDelegate <ParentClass>
@optional - (return_type) methodName:(certain_type) args; // optional delegate methods
- (return_type) methodName2:(certain_type) args; // the class who implements this delegate must implement this method.
@end

2.采用一个协议:
#import "xxxDelegate.h"
@interface xxxClassA<xxxDelegate, xxxxxxDelegate>
@end

@implementation xxxClassA

- (return_type) delegateMethod:(certain_type) args
{
// do something with the args
}

3. delegate 作为类变量:
@interface xxxClassB
@property(nonatomic, assign) id<xxxDelegate> delegate; //用assign , 否则会有引用循环。
...
@end

@implementation xxxClassB
- (void)dealloc
{
self.delegate = nil; // be a responsible delegate. not necessary .
[super dealloc];
}
@end

4. xxxClassA and xxxClassB 有什么关系:
xxxClassA *a = [[xxxClassA alloc] init];
xxxClassB *b = [[xxxClassB alloc] init];
b.delegate = a;
所以, b中可以通过调用[delegate  delegateMethod]; 而影响到 a.

Block (块) 是GCD(Grand Central Dispatch) 要执行的工作单元。 GCD是操作系统管理的一个线程池。
Block可以用做代替delegate机制的回调,也应用于并行开发(Concurrency programing)等技术中。
如何定义一个块:
1. 块的声明,(块的直接量,没名字,所以有时候也叫匿名函数):
^(argument_list){
body
};
2. 如何调用块: 
方法一:int j = ^(int n){return n*2;} (9); // j equals 18 now, (可以在直接量后面圆括号括起来要传入的参数, 块就被调用了)
方法二: 定义块指针。 return_type (^blockPointerName)(list of arguments);
如: int (^doubler)(int);
doubler = ^(int n){return n*2;};
int j = doubler(9);
以块指针作为函数的参数:
void someFunction(int (^blockArg) (int));
int (^doubler)(int ) = ^(int n){return n *2};
someFunction(doubler);
以块指针作为Objective-C方法(声明)的参数:
- (void) doSomethingWithBlockPointer: (float (^)(float)) blockPointer;
3.一个块如何访问其包围环境中的变量:
3.1 当执行流程通过块直接量时,块用于其环境中的一个本地变量的值,就是该本地变量的值。
int j  = 10;
int (^blockPtr)(int) = ^(int n) {return j + n;};
j = 20;
int k = blockPtr(5); // k is now 15, not 25.  
原因:实际上blockPtr在被赋值的时候,是用的当时j 的一个私有副本,所以这个副本j' 值为10.
3.2 块可以通过指针来访问静态和外部变量。 块当执行时会查找这些值,所以这些值不一定是定义该块时候的值。
static int j = 10;
int (^blockPtr)(int) = ^(int n){ return j +n;};
j = 20;
int k = blockPtr(5); // k is 25.
3.3 块对于本地变量的访问是只读的。
int j = 10;
void(^blockPtr)(void) = ^(void){j = 20;} ; // 编译错误。
3.4 如果本地有个变量保存了指向某个对象的指针,那么块不能修改这个变量指向别的对象,但是可以修改当前指向对象的值。
如: NSMutableArray *localArray = .......
void (^shortArray)(void) = ^(void){[localArray removeLastObject];}; // correct.
shortArray();
3.5 定义块变量: __block int integerBlockVariable;
对于块变量作用域中定义的任何块,它都是可见的,可共享的,可以修改的。
__block int j = 10;
void (^blockPtr_1) (void) = ^(void) {j += 15;};
void (^blockPtr_2) (void) = ^ (void) {j += 25;};
blockPtr_1(); // j  is now 25;
blockPtr_2(); // j is now 50;
4.块的内存管理:
4.1块其实是一个Objective-C类。块可以调用 copy, release, autorelease, 或者Block_copy(); Block_release(),来管理引用计数, 块是基于栈的,所以retain操作不起作用,必须用copy复制块(这有时候也是陷阱,不过我都没用过这么高级的东东,所以,初学者也太担心这个)。
4.2一个块在被复制的时候,它所引用的变量如果保存一个对象,那么这个对象会被保留(retain), 这个块释放时,也会释放这个对象(release).
4.3 块内调用的对于self的直接引用会导致self被保留(retain), 直接引用实例对象的变量,也会导致self 被保留(retain),方法中的本地变量,也会被保留(retain)。

5.块与函数指针的对比:
声明,定义都很像,就是* 和 ^符号的区别。
在应用上,主要的区别(我认为的):
5.1:用函数指针指向函数,你需要把函数内所用到的外部的变量,都作为参数传递给函数才可以用。
5.2: 函数指针的话,你必须事先定义这个函数,然后再声明函数指针,然后再赋值。Block你无需声明,可以用块直接量。

转自:
http://blog.163.com/saai_2007/blog/static/16945039820121171029250



0 0
原创粉丝点击