@myron-lee
2016-04-19T01:37:17.000000Z
字数 4904
阅读 1490
IOS
监听注入
类似。
#import <Foundation/Foundation.h>
@class EOCClassA;
@class EOCClassB;
@interface EOCClassA : NSObject
@property (nonatomic, strong) EOCClassB *other;
@end
@interface EOCClassB : NSObject
@property (nonatomic, strong) EOCClassA *other;
@end
说明
oc 中没有 gc,ARC 解决不了 retain cycle 问题,retain cycle 会造成内存泄露。
可能发生的地方
A block automatically retains all objects it captures.
如果 block 使用了持有 block 的对象,retain cycle 就产生了。block 会自动retain 它使用的对象。比如,我们在一个对象方法中定义了一个 block,这个 block 可以访问所有这个对象方法能访问的变量,其中就包括 self,如果在 block 中不经意的使用到了 self,那么 block 将 retain self 这个对象。如果恰好,self 对象也 retain 这个 block 对象(可能是间接的 retain),那么将会形成一个 retain cycle。比如,下面一个例子中,_fetchedData = data;
使得 block retain 了 EOCClass 对象,而 EOCClass 对象持有 EOCNetworkFetcher 对象的引用,EOCNetworkFetcher 持有 block 的引用,也就是说 EOCClass 间接的 retain block,从而形成 retain cycle,这个问题可以通过在EOCNetworkFetcher 工作完成后释放它的引用解决。
// EOCNetworkFetcher.h
#import <Foundation/Foundation.h>
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);
@interface EOCNetworkFetcher : NSObject
@property (nonatomic, strong, readonly) NSURL *url;
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler: (EOCNetworkFetcherCompletionHandler)completion;
@end
// EOCNetworkFetcher.m
#import "EOCNetworkFetcher.h"
@interface EOCNetworkFetcher ()
@property (nonatomic, strong, readwrite) NSURL *url;
@property (nonatomic, copy) EOCNetworkFetcherCompletionHandler completionHandler;
@property (nonatomic, strong) NSData *downloadedData;

@end
@implementation EOCNetworkFetcher
- (id)initWithURL:(NSURL*)url {
if ((self = [super init])) {
_url = url;
}
return self;
}
- (void)startWithCompletionHandler: (EOCNetworkFetcherCompletionHandler)completion
{
self.completionHandler = completion;
// Start the request
// Request sets downloadedData property
// When request is finished, p_requestCompleted is called
}
- (void)p_requestCompleted {
if (_completionHandler) {
_completionHandler(_downloadedData);
}
}
@end
@implementation EOCClass {
EOCNetworkFetcher *_networkFetcher;
NSData *_fetchedData;
}
- (void)downloadData {
NSURL *url = [[NSURL alloc] initWithString:
@"http://www.example.com/something.dat"];
_networkFetcher =
[[EOCNetworkFetcher alloc] initWithURL:url];
[_networkFetcher startWithCompletionHandler:^(NSData *data){ NSLog(@"Request URL %@ finished", _networkFetcher.url);
_fetchedData = data; }];
}
@end
这是 EOCClass 对象与 block 之间形成的 retain cycle。事实上,一些网络访问库,consumer 并不需要持有 networkFetcher 去 keep it alive,可以通过将 networkFetcher 放到 global 的 set 中实现。这样 EOCClass 对象与 block 之间的 retain cycle 就不那么容易实现。但是如果在 block 中使用了 networkFetcher 将会形成 networkFetcher 与 block 之间的 retain cycle,如下面的例子所示。block 会持有它使用到的对象,而 networkFetcher 通过 property 持有 block,retain cycle 形成。所以,在 block 中使用任何对象的时候都要小心
(void)downloadData {
NSURL *url = [[NSURL alloc] initWithString:
@"http://www.example.com/something.dat"];
EOCNetworkFetcher *networkFetcher =
[[EOCNetworkFetcher alloc] initWithURL:url];
[networkFetcher startWithCompletionHandler:^(NSData *data){ NSLog(@"Request URL %@ finished", networkFetcher.url);
_fetchedData = data; }];
}
The general rule is that if you don’t own an object, you should not retain it.
weak reference 不 retain 对象,并且在对象被deallocate时被设为 nil。说明
block 类似于函数指针,但实际上是一个对象,它的存储空间默认分配在 stack 上,所以只在定义的 scope 里面有效,但是可以通过给它发送 copy 消息,将存储空间转移到 heap 上前。
它的存储空间保存了 isa 指针,指向一个 Class 对象;保存了 invoke 指针,是指向 block 实现的函数指针;captured variables 保存了所有 block 使用到的对象的引用。
block 内可以访问其定义的 scope 中所有可以访问的变量,默认只能读取,使用_block 修饰才能修改(成员变量不需要显式使用_block修饰)。
使用场景
Handler,比如 CompletionHandler、ErrorHandler,在调用服务的时候直接注入 Handler,将启动代码与结束处理(响应)代码放在一起,提高代码的可读性。并且,每次调用服务都当场定义响应block,不需要像 delegate 模式中的响应函数对不同的服务进行 switch,分别响应,也就不需要保存各个服务。
CD VS Lock、synchronize
GCD 有 serial queue、concurrent queue; dispatch_sync、dispatch_async; dispatch_barrier_sync、dispatch_barrier_async 等等方法可以使得互斥同步操作更加高效的实现,比如将属性的读操作 dispatch_sync和属性的写操作dispatch_barrier_async 到一个 concurrent queue中去,可以实现多线程高效读写。
GCD VS performSelector
performSelector限制方法参数必须是对象,并且最多两个,有些场景下无法使用。使用GCD则没有此限制,并且同样支持延迟执行、支持指定在某一线程执行。
GCD VS NSBlockOperation
GCD 中使用 block,比较轻量;NSBlockOperation 是封装过的,更重,但是功能更强大,支持 Cancel、相互依赖、KVO(比如isCancelled)、优先级、重用等等。
Dispatch group