• Objective-C基础之_ weak, _ strong , __ block


     

    上一篇文章中对于block做了一个全面的剖析和理解,那么在OBjective—C的block使用中我们难免会用到以上几个关键字,其实对于__block上篇文章已经做了解释,这篇文章,我会做几个关键字的区别和总结,来加深认识和理解。 
    上篇文章知道 clang -rewrite-objc 可以将OC代码转化成C代码C++代码,如果变量加上_ weak修饰,会发现无法转化,提示:cannot create _ weak reference because the current deployment target does not support weak references 我们需要这样解决这个问题:clang -rewrite-objc -fobjc-arc -fobjc-runtime=macosx-10.13 main.m -fobjc-arc代表当前是arc环境 -fobjc-runtime=macosx-10.13:代表当前运行时环境 缺一不可 clang指令

    .m 源码
    int main(int argc, char * argv[]) {
    // @autoreleasepool {
    // return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    int a = 10;
    int b = 20;
    NSNumber *c = @(123);
    __block NSNumber *d = c;
    __weak NSNumber *f = c;
    void (^myBlock)(void) = ^{
    __strong NSNumber *e = f;
    NSLog(@"hello world %d, %d, %@, %@, %@, %@", a, b, c, d, f, e);
    };
    myBlock();
    // }
    return 0;
    }
    转化成c代码
    // block 结构体
    struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    int a;
    int b;
    NSNumber *__strong c;
    NSNumber *__weak f;
    __Block_byref_d_0 *d; // by ref
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int _b, NSNumber *__strong _c, NSNumber *__weak _f, __Block_byref_d_0 *_d, int flags=0) : a(_a), b(_b), c(_c), f(_f), d(_d->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
    }
    };
    // 我们可以看到没有__block修饰的变量和__weak修饰的对象,都没有重新生成一个__Block_byref_d_0 的结构体,只有__block修饰的才会生成这样的结构体
    int main(int argc, char * argv[]) {
     
     
    int a = 10;
    int b = 20;
    NSNumber *c = ((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), (123));
    __attribute__((__blocks__(byref))) __Block_byref_d_0 d = {(void*)0,(__Block_byref_d_0 *)&d, 33554432, sizeof(__Block_byref_d_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, c};
    __attribute__((objc_ownership(weak))) NSNumber *f = c;
    void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, f, a, b, c, (__Block_byref_d_0 *)&d, 570425344));
    ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
     
    return 0;
    }
    struct __Block_byref_d_0 {
    void *__isa;
    __Block_byref_d_0 *__forwarding;
    int __flags;
    int __size;
    void (*__Block_byref_id_object_copy)(void*, void*);
    void (*__Block_byref_id_object_dispose)(void*);
    NSNumber *__strong d;
    };
     
    // 我们可以看到没有加__block的变量,在捕获之后,都会copy出来,不管是值类型还是引用类型的,所以不可以改变内容
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_d_0 *d = __cself->d; // bound by ref
    NSNumber *__weak f = __cself->f; // bound by copy
    int a = __cself->a; // bound by copy
    int b = __cself->b; // bound by copy
    NSNumber *__strong c = __cself->c; // bound by copy
     
    __attribute__((objc_ownership(strong))) NSNumber *e = f;
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_dr_jkts5c395zs9xcx0bt_r7fx40000gn_T_main_188e34_mi_0, a, b, c, (d->__forwarding->d), f, e);
    }

    通过上述的源码,我们可以看出,只有__ block 修饰的局部变量才会生成一个结构体,这个结构体包含了变量,而block的结构体则是一个变成了结构体的指针,所以内部修改指针指向内容是可以的,而对于没有修饰的变量,值变量则是重新声明一个变量赋值相同,引用类型则是重新申明变量,指针copy,所以在内部都是无法修改外部变量的值的。

    综上所述,__ block :修饰的外部局部变量值和引用类型,都会重新生成包裹该变量的结构体,block本质结构体会声明这个结构体的指针,所以可以直接修改外部局部变量;可修饰值变量和引用变量(即普通类型和对象类型的变量); 
    没有修饰的变量:值类型和引用类型都会重新生成一个变量,值类型重新生成一个变量,将局部变量的值赋值给他;引用类型的变量,生成一个新指针,指向这个指针的copy,强引用; 
    weak :没有重新生成包裹变量的结构体,重新声明一个弱引用指针,指向这个指针的copy体,所以不可以在内部修改变量的值;只能修饰引用类型的变量,所以 weak 修饰可以防止循环引用; 
    __strong:一般使用像如下代码

    // typeof() 函数只是返回参数的类型
    __weak typeof(self) weakSelf = self;
    void (^myBlock)(void) = ^{
    __strong typeof(self) strongSelf = weakSelf;
    }

    block内部对变量生成一个强引用,防止在Block函数体执行过程中,变量被释放,block函数体执行完,引用计数器-1

     
     
     
     

  • 相关阅读:
    hadoop 2.x 简单实现wordCount
    httpClient连接超时设置
    Java io使用简介
    log4j使用教程
    F#中的自定义隐式转换
    Computation expressions and wrapper types
    Introducing 'bind'
    Understanding continuations
    Computation expressions: Introduction
    MySQL优化总结,百万级数据库优化方案
  • 原文地址:https://www.cnblogs.com/wannaGoBoy/p/9052700.html
Copyright © 2020-2023  润新知