2015-12-03 13:57:58 ci915194561 阅读数 2511

MRC下dealloc 方法

其实在MRC中dealloc方法存在的主要意义是为了
释放自身的实例变量,
移除观察者,
停止timer,
移除通知,
代理置空等。
注意MRC 下dealoc 方法一定要在最后写
[super dealloc];

ARC下 系统会帮助我们释放该对象所包含的实例变量,但是有些对象还是需要们自己去释放的(比如Core Foundation框架下的一些对象),另外通知中观察者的移除,代理置空,停止timer等
示例如下所示:
一定不能有 [super dealloc];

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter]                      removeObserver:self];//移除通知观察者
    [[XMPPManager sharedManager]                               removeFromDelegateQueue:self];//移除委托引用
    [[MyClass shareInstance]  doSomething ]//其他操作
    scrollView.delegate = nil;
    [timer invalidate];  
}
2017-06-14 18:38:37 txz_gray 阅读数 3130

最近项目突然被说会闪退,且无法重现,时有出现。接到问题后一步步排查,终于发现问题。

表现某个页面的通知观察者方法被多次调用!

原因查找:

1、通知的监听这里我写在viewDidLoad里面,多次被调用只能说明多次发送了通知,或者多次添加了观察者。

2、通知的发送确定没多次调用,而通知的监听为何会被多次添加?

3、一般我们会在dealloc方法里面移除通知,打断点发现,dealloc方法并未调用

4、通知每进一次页面添加一次,pop之后又未被移除,那就可能造成内存泄露,闪退!

解决思路也就是要确定dealloc方法为何不走!

dealloc不被调用的原因:

1、ViewController中存在定时器NSTimer,定时器一跑起来就增加了ViewController的return count,如果你不将这个timer invalidate,则控制器无法释放;

2、ViewController中有强引用代理(delegate),改为weak修饰;

3、ViewController中有Block,且有循环引用。这个也是我不能调用dealloc的真正原因。Block体内使用实例变量会造成循环引用,使得拥有这个实例的对象不能释放。 
例如你这个类叫OneViewController,有个属性是NSString *name; block的持有者也是VC的一个属性,如果你在block体中使用了self.name,那样子的话这个类就没法释放。

注意:VC持有的实例变量和@implementation下面创建的全局变量也会被循环引用

@interface GroupChpPay ()
{
    UIView *_xxView;
}
@implementation GroupChpPay
{
    UIView *_xxView;
}

即使在你的block代码中没有显式地出现"self",也会出现循环引用!就像上面的实例变量和全局变量,并不会使用self.调用,其实也会被循环引用。只要你在block里用到了self所拥有的东西!

但对于这种情况,我们无法通过加__weak声明或者__block声明去禁止block对self进行强引用或者强制增加引用计数。但我们可以通过指针来避免循环引用,具体是这么做的:

__weak typeof(self) weakSelf = self;
self.blkA = ^{
    __strong typeof(weakSelf) strongSelf = weakSelf;//加一下强引用,避免weakSelf被释放掉
    NSLog(@"%@", strongSelf->_xxView); //不会导致循环引用.
};


排查方法:

1、在添加通知的页面搜索所有 ^ 符号,也就是排查所有block方法有没有使用弱引用。基本都改好之后,dealloc方法可以被调用了,控制器销毁通知成功移除,问题解决!

2、真找不到哪里出错,最笨的方法,将可能出错的代码一段段注释排查!

还有值得一提的是,一般编译器会对需要使用weak弱引用的地方给出警告,但我这里没有警告,是在环信的SDK写的类里面,坑。

2017-06-03 11:09:59 shifang07 阅读数 360

dealloc:

ARC唯一一个留着 dealloc 方法的原因就是, 你需要释放一些不在 ARC 控制下的资源。 例如 Core Foundation 对象中调用 CFRelease() 对那些通过 malloc() 分配的内存调用 free(), 注销通知,停止 Tiner 等等。


iOS中viewController被POP后不调用dealloc的问题?


ARC下可以重写dealloc方法并在viewController被释放后自动调用,控制器在被pop后移出栈后会被释放,但有些时候会发现控制器出栈的时候不会调用dealloc方法,归根结底,是因为当前控制器被某个对象强引用了,控制器的引用计数不为0,系统无法帮你释放这部分内存。原因大致有以下几点:


控制器中NSTimer没有被销毁

viewController中存在NSTimer时,需要特别注意,当调用[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:userInfo:nil repeats:YES]

时,因为 target:self ,也就是引用了当前viewController,导致控制器的引用计数加1,如果没有将这个NSTimer 销毁,它将一直保留该viewController,无法释放,也就不会调用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer销毁。

[timer invalidate]; // 销毁timer

timer = nil; // nil


viewController中的代理不是weak属性

例如@property (nonatomic, weak) id delegate;代理要使用弱引用,如果代理属性设置为strong,则意味着delegate对视图控制器也进行了强引用,会造成循环引用。导致控制器无法被释放,最终导致内存泄漏。


viewControllerblock的循环引用

ARC下,block会把它里面的所有对象强引用,包括当前控制器self,因此有可能会出现循环引用的问题。比如viewController中有个block属性,在block中又强引用了self或者其他成员变量,那么这个viewController与自己的block属性就形成循环引用,导致viewController无法释放。

由于self__strong修饰,在 ARC 下,当编译器自动将代码中的 block 从栈拷贝到堆时,block 会强引用和持有self,而self恰好也强引用和持有了 block,就造成了传说中的循环引用。


为了避免这种情况发生,可以在变量声明时用weak修饰符修饰变量self,让 block 不强引用self,从而破除循环。


dealloc该写些什么?

在非ARC开发环境中,dealloc是类释放前,清理内存的最后机会。到底那些变量和属性该释放呢,一些特殊的类(nstimer,observer)该怎么释放?


- (void)dealloc

{

    // 1. 通知的释放

    [[NSNotificationCenter defaultCenter]removeObserver:self]; 


    // 2. delegate的释放 

    // delegate属性的赋值一般为self,虽然声明时assign,但在相关的view释放时,在之前先释放掉delegate

    // 情况一

      if (_loadingContentView) {

        _loadingContentView.delegate = nil;

        [_loadingContentView removeFromSuperview];

      }

     // 情况二 

     self.partGridView.uiGridViewDelegate = nil;

     self.partGridView = nil;


     // 3. 变量的释放

     [brandview release];

     // 4. 属性的释放

      self.labelTitle = nil; 


     // 5.定时器释放

     // 如果实在view中声明初始化的,要在 controller中view释放前先释放定时器,否则由于循环引用,而释放不掉

      if (landscape) {

           [landscape->timer invalidate];

       }

      SafeRelease(landscape);

}


iOS ARC环境下dealloc的使用

一般使用ARC的话,dealloc函数是不需要实现的,写了反而会出错。但有些特殊的情况,dealloc函数还是需要的。比如,在画面关闭的时候,需要把ViewController的某些资源释放,在viewDidDissppear不一定合适,这时dealloc里实现:


举个例子,画面上有UIWebView,它的delegate是该画面的ViewController,在WebView载入完成后,需要做某些事情,比如,把indicator停掉之类的。如果在WebView载入完成之前关闭画面的话,画面关闭后,ViewController也释放了。但由于WebView正在载入页面,而不会马上被释放,等到页面载入完毕后,回调delegateViewController)中的方法,由于此时ViewController已经被释放,所以会出错。(message sent to deallocated instance

解决办法是在dealloc中把WebViewdelegate释放。

- (void)dealloc {

    self.webView.delegate = nil;

}


ARC下,系统可以帮我们释放该对象,及其包含的对象;但是却无法释放不属于该对象的一些东西,如:由于通知中心是系统的一个单例,你在注册通知的观察者时,实际上是在通知中心注册的,这时,即使ARC下系统帮我们释放了对象,但是在通知中心的观察还是没有移除,那么当有该通知时,依然会尝试调用该对象的接受通知的方法,这可能会导致一些问题.

另外, 在你的 dealloc 方法中, 你仍然可以使用实例变量, 因为他们在这时候还没被释放掉。 dealloc 返回之前,都不会被释放。  



参考:http://blog.csdn.net/xdrt81y/article/details/10107409

:http://blog.csdn.net/musou_ldns/article/details/7673795


2015-01-30 16:26:38 AllInOrNothing 阅读数 6082

虽然现在大部分都是ARC工程,系统帮你处理内存管理,但这不等于开发者不用管理内存。比如通知的移除、baiduSDK中的变量置nil等都需要重写dealloc方法来实现。注意,ARC工程是可以重写dealloc方法并被系统调用的,但不需要手动调用父类的dealloc,手写[super dealloc]方法会报错,事实上系统会自动帮你调用父类的dealloc方法,不需要你实现。


但有些时候会发现控制器出栈的时候不会调用dealloc方法,归根结底,是因为当前控制器被某个对象强引用并“握住”了,控制器的引用计数不为0,系统无法帮你释放这部分内存。


控制器被强引用的原因:

1.block块使用不当。因为block会对方法中的变量自动retain一次。请检查控制器中block代码。

2.NSTimer没有销毁。在viewWillDisappear之前需要把控制器用到的NSTimer销毁,具体操作

NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:nil userInfo:nil repeats:YES];
[timer invalidate]; // 销毁timer
timer = nil; // 置nil
3.控制器中的代理属性为retain。应把代理属性改为assign。


若还有原因会导致dealloc方法不被调用,请告之探讨。



2017-09-15 10:59:54 pwf2006 阅读数 1237

iOS自带的NSNotification在日常使用中如果注册完不removeObserver的话会引发crash,开发者在开发过程中往往由于自己的疏忽而忘记写removeObserver,尤其在代码重构过程中很容易忽略掉.那么有没有好的办法自己实现一套通知中心的功能,而不用在observer的dealloc函数中removeObserver呢?

答案是有的,iOS开发中经常用weak来修饰类的属性,当weak指针指向的对象销毁时,weak指针指向的对象变为nil, 向nil发送任何消息都不会崩溃,有兴趣的同学可以上网查查Appleweak底层的实现原理,粗略的图如下:

Apple Weak底层Hash Map图

iOS中有一个类NSPointerArray弱引用数组,对添加到其中的类不强引用,如果对象销毁,那么NSPointerArray数组中对应的项变为nil,到这里你有想法了没有?

根据这个思路我简单写了点代码实现iOS NSNotification的功能,PWFNotification源码地址代码已经提交到github上.下面简单介绍一个如何使用,用户可以在自己的工程podfile中加上:

pod 'PWFNotification'

就可以把源码加到自己的工程中.你可以通过下面的方法注册PWFNotification:

- (void)pwf_addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;

在发通知的时候可以调用PWFNotificationCenter的下面三个方法之一:

- (void)pwf_postNotificationName:(NSString *)aName object:(id)object userInfo:(NSDictionary *)aUserInfo;

- (void)pwf_postNotificationName:(NSString *)aName object:(id)object;

- (void)pwf_postNotificationName:(NSString *)aName;

PWFNotification同时支持在主线程发通知:

[PWFNotificationCenter defaultCenter].postNotificationInMainThread = YES;

如果不设置该属性默认从当前线程发送通知.由于通知中心是一个单例的形式,时间长了通知中心会保存很多无效的observer对象(nil),我也作了相应的处理,在App内收到内存警告时,会清理一些无效的observer及相关信息.

感兴趣的同学可以去github上下载源码看一下,如果有问题请联系674423263@qq.com.

OC_Notifications(通知)

阅读数 465

没有更多推荐了,返回首页