内存泄露实例

  • object->block->object(对象强引用块,块中捕获对象)

    @interface TestViewController ()
    
    @property (copy, nonatomic) void(^testMemeoryLeakBlock)(void);
    @property (copy, nonatomic) NSString* aStr;
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
        self.aStr = @"test string";
        __weak typeof(self) weakSelf = self;
        self.testMemeoryLeakBlock = ^{
            NSLog(@"%@",self.aStr);
            NSLog(@"%@",_aStr); //block 也会捕获带下划线变量中self,
             __strong typeof(weakSelf) strongSelf = weakSelf;
            NSLog(@"%@",strongSelf.aStr);
            NSLog(@"%@",strongSelf->_aStr);
        };
    }
     - (void)dealloc{
        //重写dealloc方法,观察对象是否被释放.
        NSLog(@"dealloc method excute!");
    }
  • [NSNotificationCenter defaultCenter]addObserverForName......

    [NSNotificationCenter defaultCenter]addObserverForName...其实严格中没有出现循环引用,只是因为强引用造成对象无法释放.
    @interface TestViewController ()
    @property (strong, nonatomic) id observer;
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    }
    
    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        //这里使用weakSelf时候,可以不用移除观察者.
        __weak typeof(self) weakSelf = self;
        self.observer =   
        [[NSNotificationCenter  defaultCenter]addObserverForName:UIKeyboardDidHideNotification   
                          object:nil   
                           queue:[NSOperationQueue mainQueue]   
                      usingBlock:^(NSNotification * _Nonnull note) {
                            __strong typeof(weakSelf) strongSelf = weakSelf;
                            [strongSelf doSomeThing];
        
        }];
    }
    
    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        [[NSNotificationCenter defaultCenter]removeObserver:self.observer];
        self.observer = nil; //如果是Strong 同时必须置nil
        //[NSNotificationCenter defaultCenter]-->Observer --CopyBlock-->Self
                                     
    }
    
    - (void)dealloc{
        NSLog(@"ViewController Dealloc!");
    }
    
    - (void)doSomeThing{
    
    }
    
  • NSTimer scheduledTimerWithTimeInterval.....

    NSTimer会保留其目标对象;知道定时器失效为止,调用invalidate方法可令timer失效,另外  
    一次性的timer任务执行完也会失效;反复执行的任务容易出现循环引用,如果其他对象又保留  
    timer一定会引入循环引用,可以引入块来打破这种保留环.
    
    @interface NSTimer (invoke)
    +(NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti   
                                    block:(void(^)())block  
                                 userInfo:(id)userInfo   
                                  repeats:(BOOL)yesOrNo;
    @end
    
    @implementation NSTimer (ste_invoke)
    +(NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti  
                                        block:(void(^)())aBlock  
                                     userInfo:(id)userInfo   
                                      repeats:(BOOL)yesOrNo
    {
        return [
        self scheduledTimerWithTimeInterval:ti  
                                     target:self   
                                   selector:@selector(ste_timerFireMethod:)   
                                   userInfo:[aBlock copy ]   
                                    repeats:yesOrNo
        ];
    }
    
    +(void)ste_timerFireMethod:(NSTimer*)timer
    {
        void(^block)() = timer.userInfo;
        if (block) {
            block();
        }
    }
    @end
    
    //使用的时候;也应该注意块的循环引用
  • Core Foundation 对象的内存管理
    我们创建的Core Foundation 对象在ARC下由我们自己管理其生命周期(创建了就要对应有释放),当转换为Foundation框架下的对象时涉及到的对象方法有:

    1. __bridge: 只做类型转换,不修改相关对象的引用计数,原来的Core Foundation 对象在不用时,需要调用CFRelease 方法.
    2. __bridge_retained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对象在不用时,需要调用CFRelease 方法.
    3. __bridge_transfer:类型转换后,将该对象的引用计数交给ARC管理, Core Foundation 对象在不用时,不再需要调用 CFRelease 方法.
  • about block
    block_layout.png

对应的数据结构如下:

struct Block_descriptor {
  unsigned long int reserved;
  unsigned long int size;
  void (*copy)(void *dst, void *src);
  void (*dispose)(void *);
  };
 struct Block_layout {
  void *isa;
  int flags;
  int reserved;
  void (*invoke)(void *, ...);
  struct Block_descriptor *descriptor;
  /* Imported variables. */
};

各个字段解释:
isa 指针,所有对象都有该指针,用于实现对象相关的功能.
flags,用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用.
reserved,保留变量.
invoke,函数指针,指向具体的 block 实现的函数调用地址.
descriptor, 表示该 block 的附加描述信息,主要是 size 大小,以及 copy 和 dispose 函数的指针.
variables,capture 过来的变量,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中.

在 Objective-C 语言中,一共有 3 种类型的 block:
_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量.
_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁.
_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁.

对于block外的变量引用,block默认是将其复制到其数据结构中来实现访问的
对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的(能够修改值)
在 ARC 开启的情况下,将只会有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 类型的 block

参考链接:
https://stackoverflow.com/que...
http://blog.parse.com/learn/e...
http://blog.devtang.com/2013/...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值