[摘要]Effective Objective-C 2.0(三 )

通过委托与数据源协议进行对象间通信

原因

业务应该和数据解耦合,酱紫业务的改变不需要数据也接着改变;同样,数据存储机制的调整也不需要更改业务。

处理

如下图所示,FSJNetworkFetcher定义了一套协议接口,如FSJNetworkFetcherDelegate中得方法,FSJDataModel继承了Delegate并实现了方法,接着FSJDataModel发起了FSJNetworkFetcher请求,当FSJNetworkFetcher获得数据后回调委托方法将数据传递给委托对象。

这里FSJDataModel作为委托对象实现了Delegate方法
委托模式

//FSJNetworkFetcherDelegate.h
@protocol FSJNetworkFetcherDelegate
-(void)networkFetcher:(FSJNetworkFetcher*)fetcher didReceiveData:(NSData*)data;
-(void)networkFetcher:(FSJNetworkFetcher*)fetcher didFailWithError:(NSError*)error;
@end

//FSJNetworkFetcher.h
@interface FSJNetworkFetcher: NSObject
@property (nonatomic, weak)id <FSJNetworkFetcherDelegate> delegate;
@end

@implementation
...
NSData *data = /*data from fetcher*/
if([_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)])
{
    [_delegate networkFetcher:self didReceiveData:data];
}
...
@end

//FSJDataModel.m
@interface FSJDataModel()<FSJNetworkFetcherDelegate>
@end
@implementation

-(id)init{
    if(self = [super init])
    {
        FSJNetworkFetcher *fetcher = [[FSJNetworkFetcher alloc] init];
        fetcher.delegate = self;
        ...
    }
    return self;
}

-(void)networkFetcher:(FSJNetworkFetcher*)fetcher didReceiveData:(NSData*)data
{
    /*Handle Data*/
}
-(void)networkFetcher:(FSJNetworkFetcher*)fetcher didFailWithError:(NSError*)error
{
    /*Handle Data*/
}
@end

上面的代码需要注意属性delegate对象必须是weak特质,原因如下图,DataModel声明了对象NetworkFetcher,并将NetworkFetcher的delegate 赋值为self,也就是NetworkFetcher对象持有DataModel,同时发起了NetworkFetcher请求,NetworkFetcher获得数据检验self是否实现delegate方法,如果实现,执行。
假如delegate特质为strong,会造成DataModel 与NetworkFetcher循环引用,导致内存泄露。
拥有关系与非拥有关系

  • 委托协议可以用@optional或@required来声明接口是可选还是必要,可选的接口需要用respondsToSelector:方法来检查是否实现

  • 假如委托方法需要调用多次,那么将respondsToSelector:的检查结果缓存起来能够优化执行速度

//声明了缓存结构体
@interface FSJNetworkFetcher(){
    struct {
        BOOL didReceiveData = 1;
        BOOL didFailWithError = 1;
    } _delegateFlag;
}

//在设置delegate的时候就进行相关方法实现的检查
-(void)setDelegate:(id<FSJNetworkFetcherDelegate>)delegate{
    _delegate = delegate;
    _delegateFlag.didReceiveData = [_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
    _delegateFlag.didFailWithError = [_delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)];
}

//在代码实现的时候就进行设置
_delegateFlag.didReceiveData = 1;

//调用之前检查缓存结构体
if(_delegateFlag.didReceiveData){
//Yes, flag set
}

分类机制

详见:
http://blog.csdn.net/shawjan/article/details/48847239

通过协议提供匿名对象

假如你不想让外部知道你实现的类,你可以通过协议来隐藏类名。之所以能够这么实现,主要是遵循了FSJDelegate协议的对象,都可以赋值给在另外一个类中声明的delegate,并且通过这个delegate来响应指定的方法。如下面所示,这样外部就不知道调用类的名字。

@property (nonatomic, weak) id <FSJDelegate> delegate;

用“僵尸对象”调试内存管理问题

僵尸对象

僵尸对象是Xcode提供的一项非常方便的调试功能,启动这项功能后,运行期系统会把所有已经回收的实例转化成特殊的“僵尸对象”,而不会真正的回收他们。这种对象所在的核心内存无法重用,因此不可能遭到覆写。
僵尸对象收到消息后,会抛出异常,其中准确说明了发送过来的消息,并描述了回收之前的那个对象。

这项功能在非ARC环境会特别有用,在ARC更复杂的代码环境中也是很有用的。
启动方法:Edit Scheme → Run → 选择Diagnostics → 勾选Enable Zombie Objects
僵尸对象

原理
  • 开启了僵尸对象调试功能,当某类的对象声明周期结束时,系统会从_NSZombie_模板类中复制出来创建一个新类_NSZombie_OriginalClass,系统并不会把对象的内存释放掉,但是这块内存无法复用。同时系统修改对象的isa指针指向_NSZombie_OriginalClass僵尸类,至此,原对象转变为僵尸对象。
  • 当僵尸对象收到消息时,僵尸类能够响应所有的选择子,响应方式为:打印一条包含消息内容及其接受者的消息,然后终止程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值