iOS 笔记之 Block

来源:互联网 发布:腾讯云怎么解析cn域名 编辑:程序博客网 时间:2024/06/02 19:35

介绍一下OC中,ARC模式,使用block引起循环引用的问题


先写结论:(直接贴下面的代码,结论在此代码中)

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    self.view.backgroundColor = [UIColor yellowColor];        NSLog(@"address:%p",self);    __weak typeof(self) weakSelf = self;        <span style="color:#ff0000;">/*      *(一)     *     * 使用 Block 的对象 作为:     * 成员变量     * 结论:作为成员变量的时候,self参与持有,所以可能形成(self->blockObj->block->self)三者的循环引用     * 解决方式:     *          对 self 和 成员变量使用:__weak     */    /*</span>    self.testObj = [[TestBlock alloc] init];    [self.testObj testCallWithBlock:^(id result) {                // (1) leak [self & TestBlock]        //id obj = self.testObj;        //NSLog(@"address_block:%p",obj);                // (2) leak [self & TestBlock]        //id obj = self;        //NSLog(@"address_block:%p",obj);                // (3) unLeak        //NSLog(@"testCallWithBlock_end");                // (4) unLeak        //id obj = weakSelf;        //NSLog(@"address_block:%p",obj);                // (5) unLeak        //id obj = weakSelf.testObj;        //NSLog(@"address_block:%p",obj);            }];     */        <span style="color:#ff0000;">/*     *(二)     *     * 使用 Block 的对象 作为:     * 局部变量     * 结论:作为局部变量的时候,self不参与持有,所以self不会形成循环引用,但是,     *      局部变量可能引用自己,形成循环引用(下面情形(1))。     * 解决方式:     *      对此局部变量使用 __weak     */</span>    TestBlock *tempTestObj = [[TestBlock alloc] init];    __weak typeof(tempTestObj) weakBlockObj = tempTestObj;    [tempTestObj testCallWithBlock:^(id result) {                // (1) leak [TestBlock]        //id obj = tempTestObj;        //NSLog(@"address_block:%p",obj);                // (2) unLeak        id obj = weakBlockObj;        NSLog(@"address_block:%p",obj);                // (3) unLeak        //id obj = self;        //NSLog(@"address_block:%p",obj);                // (4) unLeak        //NSLog(@"testCallWithBlock_end");                // (5) unLeak        //id obj = weakSelf;        //NSLog(@"address_block:%p",obj);            }];}


完整测试代码如下:

////  ViewController.m//  BlockTest////  Created by liuchaoran on 15/3/19.//  Copyright (c) 2015年 liuchaoran. All rights reserved.///* * 测试思路: * 创建另一个 TestViewController,展示这个界面 2 秒,再 dismiss 此界面。 * (如果单纯这样一个空的 TestViewController ,在 dismiss 的时候,毫无疑问是要被释放的,不解释)。 * 在 TestViewController 创建成功后马上调用 TestBlock ,TestBlock 3 秒返回。 * 也就是说,TestBlock 在 TestViewController 消失之后才返回结果,这时候看一下 TestBlock 和 TestViewController 是否被释放。 */#import "ViewController.h"#import "TestViewController.h"@interface ViewController ()@property(nonatomic,strong)TestViewController *testVc;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        self.view.backgroundColor = [UIColor whiteColor];        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];    button.frame = CGRectMake(50, 100, 200, 50);    [button setTitle:@"推出下个页面" forState:UIControlStateNormal];    [button setBackgroundColor:[UIColor blackColor]];    [button addTarget:self action:@selector(pushNext) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:button];        TestViewController *tv = [[TestViewController alloc] init];    self.testVc = tv;}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}-(void)pushNext{    NSLog(@"pushNext_start");    [self presentViewController:self.testVc animated:NO completion:^{        NSLog(@"presentViewController_present_complete");    }];    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(popNext) userInfo:nil repeats:NO];}-(void)popNext{    NSLog(@"popNext_start");    [self.testVc dismissViewControllerAnimated:NO completion:^{        NSLog(@"presentViewController_dismiss_complete");    }];    self.testVc = nil;}@end

////  TestViewController.m//  BlockTest////  Created by liuchaoran on 15/3/19.//  Copyright (c) 2015年 liuchaoran. All rights reserved.//#import "TestViewController.h"#import "TestBlock.h"@interface TestViewController ()@property(nonatomic,strong)TestBlock *testObj;@end@implementation TestViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    self.view.backgroundColor = [UIColor yellowColor];        NSLog(@"address:%p",self);    __weak typeof(self) weakSelf = self;        /*      *(一)     *     * 使用 Block 的对象 作为:     * 成员变量     * 结论:作为成员变量的时候,self参与持有,所以可能形成(self->blockObj->block->self)三者的循环引用     * 解决方式:     *          对 self 和 成员变量使用:__weak     */    /*    self.testObj = [[TestBlock alloc] init];    [self.testObj testCallWithBlock:^(id result) {                // (1) leak [self & TestBlock]        //id obj = self.testObj;        //NSLog(@"address_block:%p",obj);                // (2) leak [self & TestBlock]        //id obj = self;        //NSLog(@"address_block:%p",obj);                // (3) unLeak        //NSLog(@"testCallWithBlock_end");                // (4) unLeak        //id obj = weakSelf;        //NSLog(@"address_block:%p",obj);                // (5) unLeak        //id obj = weakSelf.testObj;        //NSLog(@"address_block:%p",obj);            }];     */        /*     *(二)     *     * 使用 Block 的对象 作为:     * 局部变量     * 结论:作为局部变量的时候,self不参与持有,所以self不会形成循环引用,但是,     *      局部变量可能引用自己,形成循环引用(下面情形(1))。     * 解决方式:     *      对此局部变量使用 __weak     */    TestBlock *tempTestObj = [[TestBlock alloc] init];    __weak typeof(tempTestObj) weakBlockObj = tempTestObj;    [tempTestObj testCallWithBlock:^(id result) {                // (1) leak [TestBlock]        //id obj = tempTestObj;        //NSLog(@"address_block:%p",obj);                // (2) unLeak        id obj = weakBlockObj;        NSLog(@"address_block:%p",obj);                // (3) unLeak        //id obj = self;        //NSLog(@"address_block:%p",obj);                // (4) unLeak        //NSLog(@"testCallWithBlock_end");                // (5) unLeak        //id obj = weakSelf;        //NSLog(@"address_block:%p",obj);            }];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}-(void)dealloc{    NSLog(@"TestViewController_dealloc");}@end

////  TestBlock.h//  BlockTest////  Created by liuchaoran on 15/3/19.//  Copyright (c) 2015年 liuchaoran. All rights reserved.//#import <Foundation/Foundation.h>typedef void (^myBlock)(id result);@interface TestBlock : NSObject@property(nonatomic,strong)myBlock completionBlock;-(void)testCallWithBlock:(myBlock)returnBlock;@end

////  TestBlock.m//  BlockTest////  Created by liuchaoran on 15/3/19.//  Copyright (c) 2015年 liuchaoran. All rights reserved.//#import "TestBlock.h"@implementation TestBlock-(void)dealloc{    NSLog(@"TestBlock_dealloc");}-(void)testCallWithBlock:(myBlock)returnBlock{    self.completionBlock = [returnBlock copy];    [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(end) userInfo:nil repeats:NO];}-(void)end{    if (self.completionBlock) {        self.completionBlock(@"shit");    }}@end



0 0