设为首页 加入收藏

TOP

block本质探寻五之atuto类型局部实例对象(一)
2019-08-26 07:06:25 】 浏览:94
Tags:block 本质 探寻 atuto 类型 局部 实例 对象

说明:阅读本文章,请参考之前的block文章加以理解;

一、栈区block分析

//代码

//ARC
void test1()
{
    {
        Person *per = [[Person alloc] init];
        per.age = 10;
        ^{
            NSLog(@"age:%d", per.age);
        };
    }
    
    NSLog(@"-------1");
}

 

//打印

2019-01-14 17:24:12.118653+0800 MJ_TEST[6638:285938] Person dealloc
2019-01-14 17:24:12.118934+0800 MJ_TEST[6638:285938] -------1
Program ended with exit code: 0 

分析:

<1>block代码内部引用的Person实例对象先于输出语句销毁,因为per仅限于大括号内,但此时block销毁了没有?往下看;

<2>上述block代码块并没有被指针持有,接下来看看指针持有的情况;

//代码

typedef void(^MyBlock)(void);

//ARC
void test2()
{
    MyBlock block;
    
    {
        Person *per = [[Person alloc] init];
        per.age = 10;
        block = ^{
            NSLog(@"age:%d", per.age);
        };
    }
    
    NSLog(@"-------1");
}

//打印

2019-01-14 17:34:58.473267+0800 MJ_TEST[6824:293129] -------1
2019-01-14 17:34:58.473705+0800 MJ_TEST[6824:293129] Person dealloc
Program ended with exit code: 0

分析:Person实例对象后于输出语句销毁,为什么有指针持有,顺序就变了?

<1>等号左边:是一个auto类型的局部的block指针变量,存放在栈区;等号右边:是一个block代码块(对象),也是一个局部对象,存放在栈区;

<2>在ARC模式下,如果有指针持有(默认是强指针,修饰符为__strong)一个局部的block对象,系统会自动copy该block对象从栈区到堆区;

补充:其他三种情况——block作为函数返回值、含usingBlock方法(如数据的枚举方法)、GCD的应用(自己可以验证,此处不再赘述);

那么,我们再看看MRC的情况

//打印————test1()和test2()

2019-01-14 17:56:46.641171+0800 MJ_TEST[7171:306788] -------1
Program ended with exit code: 0

分析:为什么per对象没有销毁?——因为需要手动释放;

//代码

[per release];

//打印————test1()和test2()

2019-01-14 17:59:39.091313+0800 MJ_TEST[7243:309139] Person dealloc
2019-01-14 17:59:39.091974+0800 MJ_TEST[7243:309139] -------1
2019-01-14 17:59:39.092013+0800 MJ_TEST[7243:309139] Person dealloc
2019-01-14 17:59:39.092086+0800 MJ_TEST[7243:309139] -------1
Program ended with exit code: 0

分析:

<1>此时的block对象的作用域在第一个大括号范围内,超出则被释放;

<2>Person实例对象被捕获到block对象结构体体中,同时其作用域也仅限于第一个大括号内,因此超出同样被释放;

 

二、堆区block分析

1)类型分析——ARC

//strong类型

执行上述test2()方法,我们知道系统会自动将block对象从栈区copy到堆区;同时,Person实例对象会被捕捉到block对象的结构体中,如下

struct __test2_block_impl_0 {
  struct __block_impl impl;
  struct __test2_block_desc_0* Desc;
  Person *per;
  __test2_block_impl_0(void *fp, struct __test2_block_desc_0 *desc, Person *_per, int flags=0) : per(_per) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

分析:可以看到per是一个指针变量,而该指针变量默认修饰符为__strong;修改代码

 __strong Person *per = [[Person alloc] init];

clang命令:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 main.m

说明:

<1>该命令行,只针对ARC模式下,MRC模式下,如果有release语句会报错;

<2>该命令行,是解决ARC模式下,实例对象为__weak类型,转成C++代码;

struct __test2_block_impl_0 {
  struct __block_impl impl;
  struct __test2_block_desc_0* Desc;
  Person *__strong per;
  __test2_block_impl_0(void *fp, struct __test2_block_desc_0 *desc, Person *__strong _per, int flags=0) : per(_per) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

 分析:因此,一般的指针变量,默认修饰符为__strong;

 

//weak类型

//代码

//ARC
void test2()
{
    MyBlock block;
    
    {
        Person *per = [[Person alloc] init];
        per.age = 10;
        __weak Person *weakPer = per;
        block = ^{
            NSLog(@"age:%d", weakPer.age);
        };
//        [per release];
    }
    
    NSLog(@"----
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇presentedViewController 和 pres.. 下一篇UIPickerView基本使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目