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你无需声明,可以用块直接量。 |
|