通知不在dealloc中ios removeobserverr为什么会崩溃

“自释放”在iOS开发中的应用 - 庞海礁的个人空间
转载请注明出处:
今天,跟大家聊聊“自释放”思想在iOS开发中的应用,何为“自释放”?可以简单的理解为对象在生命周期结束后自动清理回收所有与其相关的资源或链接,这个清理不仅仅包括对象内存的回收,还包括对象解耦以及附属事件的清理等,比如定时器的自我停止、KVO对象的监听移除等
对象内存的回收
开发中,对象管理的基本原则——谁创建谁释放。但是,非ARC工程中,我们会用autorelease来标记一个对象,告诉编辑器,这个对象我不负责释放,此时,这个对象就变成了“自释放”对象,当其不再需要时,系统就会自动回收其内存。而ARC工程中,所有对象对于我们来说都是自释放对象,很高兴,我们不再需要处处留意内存泄露的问题,可以把更多的精力放在业务逻辑上,但是这并不意味着真的没有内存泄露,试试这个工具,也许你会有意想不到的收获。
定时器的自释放
定时器与一般对象不同,当创建完定时器后,其并不会自我释放,需要在适当时刻invalidate。在实际开发中,也许你经常会这样创建定时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(onTimerCount) userInfo:nil repeats:YES];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(onTimerCount) userInfo:nil repeats:YES];
然后在dealloc函数中将定时器invalidate。很遗憾,你会发现程序永远也不会执行到dealloc函数,因为NSTimer强引用target对象,循环引用的出现必然导致内存泄露。此时,你肯定非常想要一个weak target的定时器,很高兴,很好的满足了你的需求。但是,Timer仍然没有自我释放,你仍然需要在dealloc中将其invalidate。那么,如何才能不写invalidate?定时器能否自释放?我们先把这个问题放在一边,接着往下看
KVO的自释放
iOS开发中,经常会用到消息通知及KVO,也许你会这样写代码
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNotice) name:@"NoticeIdentifier" object:nil];
[self addObserver:target forKeyPath:@"keyPath" options:NSKeyValueObservingOptionNew context:nil];
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"NoticeIdentifier" object:nil];
[self removeObserver:target forKeyPath:@"keyPath"];
12345678910
- (void)viewDidLoad {&&&&[super viewDidLoad];&&&&[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNotice) name:@"NoticeIdentifier" object:nil];&&&&[self addObserver:target forKeyPath:@"keyPath" options:NSKeyValueObservingOptionNew context:nil];}&- (void)dealloc {&&&&[[NSNotificationCenter defaultCenter] removeObserver:self name:@"NoticeIdentifier" object:nil];&&&&[self removeObserver:target forKeyPath:@"keyPath"];}
随着时间的积累,你会非常习惯这种写法,并且苹果也是这样推荐的。但是慢慢你会发现所有对象的Dealloc函数都只做了这一件事,能不能不做这件事?也许会是一个不错的选择,Demo可以这样写
[self.KVOController observe:clock keyPath:@"date" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(ClockView *clockView, Clock *clock, NSDictionary *change) {
clockView.date = change[NSKeyValueChangeNewKey];
[self.KVOController observe:clock keyPath:@"date" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(ClockView *clockView, Clock *clock, NSDictionary *change) {&&&&clockView.date = change[NSKeyValueChangeNewKey];}];
的实现原理可以查看这篇,通过自释放的实现,程序猿不再关心remove监听。但是其还是有一定的局限性——对象无法监听自己的属性,如果你的代码是这样的
[self.KVOController observe:self keyPath:@"date" options:NSKeyValueObservingOptionNew block:^(NSDictionary *change) {
[self.KVOController observe:self keyPath:@"date" options:NSKeyValueObservingOptionNew block:^(NSDictionary *change) {&&&&// to do}];
很遗憾,循环引用的问题又出现,因为中的NSMapTable对象会retain key对象,具体代码如下
[_objectInfosMap setObject:infos forKey:object];
[_objectInfosMap setObject:infos forKey:object];
那么,是如何做到自释放的?可以归纳为四个字——动态属性。其为观察者绑定动态属性self.KVOController,动态绑定的KVOController会随着观察者的释放而释放,KVOController在自己的dealloc函数中移除KVO监听,巧妙的将观察者的remove转移到其动态属性的dealloc函数中。
可是,这又有什么用?对象仍然无法监听自己的属性,还是要重写set函数。也许会改变你的想法,其和来自同一人,代码可以这样写
self.anObservation = [HTBKVObservation observe:anObjectToObserve keyPath:@"observeMe" options:0 callback:^(HTBKVObservation *observation, NSDictionary *changeDictionary) {
self.anObservation = [HTBKVObservation observe:anObjectToObserve keyPath:@"observeMe" options:0 callback:^(HTBKVObservation *observation, NSDictionary *changeDictionary) {&& // to do}];
并没用采用动态属性,而是采用属性的方式实现自释放。可以监控对象自己的属性,但是需要创建属性HTBKVObservation。 我对其做了一点扩展,方便使用,代码可以这样写
[self observe:self keyPath:@"KVOPath" options:NSKeyValueObservingOptionNew callback:^(HTBKVObservation *observation, NSDictionary *changeDictionary) {
[self observe:self keyPath:@"KVOPath" options:NSKeyValueObservingOptionNew callback:^(HTBKVObservation *observation, NSDictionary *changeDictionary) {&& // to do}];
和通过属性或动态属性巧妙的将KVO的remove转移给第三者,实现了KVO事件的解耦,为自释放的实现提供了一种借鉴思路
NSNotification的自释放
谈完 KVO,再来谈谈NSNotification。针对Notification,做了很好的封装,网上有很多介绍其如何使用的文章,在此不再累述。直接看代码
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] subscribeNext:^(id x) {
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] subscribeNext:^(id x) {&&&&&&&&// to do&&&&}];
简单明了,当观察者dealloc,很遗憾,NSNotification并没用移除,因为对象并没用自释放,正确代码应该是这样
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidChangeFrameNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {&&&&&&&&// to do&&&&}];
自释放的原理与不同,其并不是通过属性或者动态属性的方式实现,而是通过swizzling观察对象的dealloc函数,在自定义dealloc函数实施清理,但不是默认清理,需要我们告诉它willDeallocSignal的时候完成所有清理工作。
除了定时器、KVO、NSNotification,包括封装的某个功能对象,比如HttpRequest,或者数据库ListSql等,合理的利用自释放可以给使用者带来更多的便利,同时也会减少 crash 产生的概率。实现自释放的方法可以总结为以下三种方式
动态属性的自释放
@property 的自释放
swizzling dealloc的自释放
可以根据具体业务或者设计思想选择对应的实现方式,这是一种思想,更是一个习惯。相信你会爱上它,毕竟谁不喜欢简洁的实现方式了!
后记: 好久没有更新文章,一是最近任务比较重,接手老代码,几千行的Controller实在无能为力,只能重写。如今,面对不到300行的Controller还是挺有成就感。生命不息,折腾不止!二是想为大家分享一点干货,不敢轻易提笔。依旧,记得,感谢大家来访!
Theme | Powered byremoveobserver在的,什么的地方使用,dealloc_理工学科_育才科教解答网
removeobserver在的,什么的地方使用,dealloc
编辑: 育才科教解答网 &&&来源:用户发布&&&发布时间:&&&查看次数:28
removeobserver在的,什么的地方使用嗳哟,dealloc
该问题暂无交流。
理工学科相关
更多相关内容
本站内容来自网友发布,本站无法保证其部分内容的正确性,请用户一定仔细辨别。
[] &&[联系QQ:885&971&98] &
黑ICP备号&在前一篇文章中我们介绍了OC中很常用的两个技术:KVC和KVO:&,今天我们来看一下OC中另外的一个常用技术:通知(Nofitication)其实这里的通知和之前说到的KVO功能很想,也是用于监听操作的,但是和KVO不同的是,KVO只用来监听属性值的变化,这个发送监听的操作是系统控制的,我们控制不了,我们只能控制监听操作,类似于Android中系统发送的广播,我们只能接受。但是通知就不一样了,他的监听发送也是又我们自己控制,我们可以在任何地方任何时机发送一个通知,类似于Android中开发者自己发送的广播。从这一点看来,通知的使用场景更为广泛了。下面就来看一下例子:还是护士和小孩的那个例子Children.h//
Children.h
Created by jiangwei on 14-10-16.
Copyright (c) 2014年 jiangwei. All rights reserved.
#import &Foundation/Foundation.h&
@interface Children : NSObject
@property NSInteger *hapyV
定义了一个属性:hapyValueChildren.m//
Children.m
Created by jiangwei on 14-10-16.
Copyright (c) 2014年 jiangwei. All rights reserved.
#import &Children.h&
@implementation Children
- (id) init{
self = [super init];
if(self != nil){
//启动定时器
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
self.hapyValue= 100;
- (void) timerAction:(NSTimer *) timer{
//使用set方法修改属性值,才能触发KVO
_hapyValue--;
NSLog(@&%@&,_hapyValue);
if(_hapyValue &80){
//发送通知
//这里和KVO的区别,我们可以手动的发送通知
//注意通知的名称,传递的参数必须和定义通知的地方的参数值要一致
//将Children对象传递过去
[[NSNotificationCenter defaultCenter] postNotificationName:@&happyValueNotification& object:self];
定义了一个定时器,但是我们看到这里的timerAction方法中就开始发送一个通知了://发送通知
//这里和KVO的区别,我们可以手动的发送通知
//注意通知的名称,传递的参数必须和定义通知的地方的参数值要一致
//将Children对象传递过去
[[NSNotificationCenter defaultCenter] postNotificationName:@&happyValueNotification& object:self];我们在属性值发生变化的地方发送一个通知:NSNotificationCenter第一个参数:通知的名称,这个名称必须和后面接受通知的名称一致第二个参数:可以传递的一个参数对象Nure.h//
Created by jiangwei on 14-10-16.
Copyright (c) 2014年 jiangwei. All rights reserved.
#import &Foundation/Foundation.h&
@interface Nure : NSObject
Created by jiangwei on 14-10-16.
Copyright (c) 2014年 jiangwei. All rights reserved.
#import &Nure.h&
#import &Children.h&
@implementation Nure
- (id) init{
self = [super init];
if(self != nil){
//监听一个通知,当收到通知时,调用notificationAction方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction) name:@&happyValueNotification& object:nil];
- (void) notificationAction:(NSNotification *)notification{
//这里我们拿到Children对象进行操作
Children *children = notification.
NSLog(@&触发通知&);
- (void)dealloc{
//移除指定的通知,不然会造成内存泄露
[[NSNotificationCenter defaultCenter] removeObserver:self name:@&happyValueNotification& object:nil];
//Children对象可以添加多个通知
//下面的方法是可以移除Children中所有通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
在Nure类中我们开始接受通知了://监听一个通知,当收到通知时,调用notificationAction方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction) name:@&happyValueNotification& object:nil];使用addObserver方法来监听通知第一个参数:监听者对象第二个参数:监听处理逻辑的方法第三个参数:通知的名称第四个参数:通知发送的时候传递过来的参数对象1、处理通知的方法- (void) notificationAction:(NSNotification *)notification{
//这里我们拿到Children对象进行操作
Children *children = notification.
NSLog(@&触发通知&);
}这里会传递一个NSNotification对象,通过object属性可以获取到监听对象了,因为我们在发送通知的时候传递过来的这个对象。那么这里我们就可以获取监听对象的属性值了,但是这里我们如果想知道属性值变化前和变化后的值,我们可以在Children类中在定义一个属性专门用来记录旧的属性值,这样就可以了。2、销毁方法- (void)dealloc{
//移除指定的通知,不然会造成内存泄露
[[NSNotificationCenter defaultCenter] removeObserver:self name:@&happyValueNotification& object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}在销毁的方法中,我们可以需要移除监听者,传递过去通知名但是这里我们会注意到,还有一个方法:removeObserver方法,是用来移除所有监听者的,因为可能有多个监听者。总结OC中KVO操作和通知都是很重要的一个操作,他们的原理是基于观察者模式的,但是KVO操作没有通知灵活。但是KVO也有自己的优点,比如可以记录新旧值,这个通知就比较麻烦点了,所以我们在使用的时候视情况而定,一般监听属性值变化的我们还是使用KVO.
本文已收录于以下专栏:
相关文章推荐
作用:NSNotificationCenter是专门供程序中不同类间的消息通信而设置的.
注册通知:即要在什么地方接受消息
             &#16...
NSArray *localNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
  ...
人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..
在实际的开发中,通知这一手段还是比较常用的。那今天就详细讲讲通知。
1.通知中心(NSNotificationCenter)实际是在程序内部提供了一种广播机制。把接收到的消息,根据内部的消息转发表,...
先看api的文档:
addObserver:selector:name:object:
Adds an entry to the receiver’s dispatch table...
在UIViewController里面注册通知,页面消失时移除通知。你这边可要注意了,一定要成双成对出现,如果你只在viewWillAppear 中 addObserver没有在viewWillDis...
//*****************************************************************************
-8通知中心
//-键盘位置改变...
他的最新文章
讲师: 许鹏
讲师:董付国
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)今天看啥 热点:
ios 的通知机制,包括通知发布,通知监听,通知移除。
1.通知发布
要发布通知前,要先创建通知对象,一个通知对象包括
通知发布者:发布通知到通知中心;
通知中心:接收通知发布者发布的通知,并转发给通知接收者。
通知接受者:接收从通知中心发布的通知。
一个通知对象要包含的内容:
1. (NSString *) // 通知的名称
2. (id) // 通知发布者
3. (NSDictionary *)userI // 一些额外的信息(通知发布者传递给通知接收者的信息内容)
1.创建一个通知(NSNotification)对象方法:
+ (instancetype)notificationWithName:(NSString *)name object:(id)O
+ (instancetype)notificationWithName:(NSString *)name object:(id)Object userInfo:(NSDictionary *)UserI
- (instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userI
2.通知中心(NSNotificationCenter)提供了相应的方法来帮助发布通知
- (void)postNotification:(NSNotification *)
发布一个notification通知,可在notification对象中设置通知的名称、通知发布者、额外信息等
- (void)postNotificationName:(NSString *)Name object:(id)O
发布一个名称为Name的通知,Object为这个通知的发布者
- (void)postNotificationName:(NSString *)Name object:(id)Object userInfo:(NSDictionary *)UserI
发布一个名称为name通知,object为通知发布者,userinfo为额外信息。
3.通知中心(NSNotificationCenter)提供了方法来注册一个监听通知的监听器(Observer)
- (void)addObserver:(id)observer selector:(SEL)Selector name:(NSString *)Name object:(id)O
observer:监听器,即谁要接收这个通知
Selector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入
Name:通知的名称。如果为nil,那么无论通知的名称是什么,监听器都能收到这个通知
Object:通知发布者。如果为anObject和aName都为nil,监听器都收到所有的通知
- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))
name:通知的名称
obj:通知发布者
block:收到对应的通知时,会回调这个block
queue:决定了block在哪个操作队列中执行,如果传nil,默认在当前操作队列中同步执行
4.通知中心不会保留(retain)监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃
通知中心提供了相应的方法来取消注册监听器
- (void)removeObserver:(id)
- (void)removeObserver:(id)observer name:(NSString *)Name object:(id)O
一般在监听器销毁之前取消注册(如在监听器中加入下列代码):
- (void)dealloc {
[superdealloc]; // 非ARC中需要调用此句
& & [[NSNotificationCenterdefaultCenter] removeObserver:self];
& & 我们经常需要在键盘弹出或者隐藏的时候做一些特定的操作,因此需要监听键盘的状态
& & 键盘状态改变的时候,系统会发出一些特定的通知
& & UIKeyboardWillShowNotification // 键盘即将显示
& & UIKeyboardDidShowNotification // 键盘显示完毕
& & UIKeyboardWillHideNotification // 键盘即将隐藏
& & UIKeyboardDidHideNotification // 键盘隐藏完毕
& & UIKeyboardWillChangeFrameNotification // 键盘的位置尺寸即将发生改变
& & UIKeyboardDidChangeFrameNotification // 键盘的位置尺寸改变完毕
& & 系统发出键盘通知时,会附带一下跟键盘有关的额外信息(字典),字典常见的key如下:
& & UIKeyboardFrameBeginUserInfoKey // 键盘刚开始的frame
& & UIKeyboardFrameEndUserInfoKey // 键盘最终的frame(动画执行完毕后)
& & UIKeyboardAnimationDurationUserInfoKey // 键盘动画的时间
& & UIKeyboardAnimationCurveUserInfoKey // 键盘动画的执行节奏(快慢)
& 由于键盘的通知是系统自动的,因此可以不用创建通知,只需要注册一个监听器监听即可,当收到相应的通知去执行方法。 & &
相关搜索:
相关阅读:
相关频道:
IOS教程最近更新}

我要回帖

更多关于 removeobserver崩溃 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信