內存泄露實例

  • object->block->object(對象強引用塊,塊中捕獲對象)objective-c

    @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.....app

    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

對應的數據結構以下:ide

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 時會被銷燬.ui

對於block外的變量引用,block默認是將其複製到其數據結構中來實現訪問的
對於用 __block 修飾的外部變量引用,block 是複製其引用地址來實現訪問的(可以修改值)
在 ARC 開啓的狀況下,將只會有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 類型的 blockatom

參考連接:
https://stackoverflow.com/que...
http://blog.parse.com/learn/e...
http://blog.devtang.com/2013/...spa

相關文章
相關標籤/搜索