block为什么用copy

8 篇文章 0 订阅
 

block为什么用copy? 


(1)block


- (void)viewDidLoad {

    [super viewDidLoad];

    __block int a=10;

    NSLog(@"a=%d",a);

    void (^blockName)()=^{

        a=20;

    };

    NSLog(@"a=%d",a);

    blockName();

    NSLog(@"a=%d",a);

}


——以上输出结果是10,10,20。


——只要在变量前面增加__block,在block里面就可以修改该变量的值。当然也有其他方法如添加static等。

——如何能实现,需要查看底层代码,也就是用C语言写成的运行时代码。在终端利用clang -rewrite-objc .m文件名,把文件转为.cpp的C++底层代码,可以分析底层实现的原理,可以用open .cpp文件名,打开查看。

——核心原理是,因为有一个__forwarding参数,每次输出都是调用a.__forwarding->a的值。而且block本质上就是一个指向结构体的地址。


(2)运行时,平时我们写得代码其实最终都会转成运行时代码,效率快。但是我们一般用OC写。如果非要使用运行时代码方式书写,可以增加下面的类。


#import <objc/message.h>//需要用到发送消息的时候,设置函数的时候

#import <objc/runtime.h>//里面有一些特殊的函数


我们平时使用的方法,其实就是消息机制,用得就是objc_msgSend这个函数。我们只要包含了上面的头文件<objc/message.h>,也可以用这个函数写代码。


——使用价值之一。我们平时的分类一般只能扩充一个类的方法,而不能扩充它的成员属性。而使用的某些方法(如下)就可以为类动态地扩充成员属性。


static double heightKey;


-(void)setHeight:(double)height{

    objc_setAssociatedObject(self, &heightKey, @(height), OBJC_ASSOCIATION_ASSIGN);

}


-(double)height{

    return [objc_getAssociatedObject(self, &heightKey) doubleValue];

}


——遍历类的成员变量(用户就是可以遍历出所有变量统一操作,比如encode或者decode之类的操作)



#import "ViewController.h"

#import "Person.h"

#import <objc/message.h>

#import <objc/runtime.h>


@interface ViewController ()


@end


@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    

    unsigned int count=0;

    //可以获得类的所有成员属性,默认指向0,即类的第一个成员属性

    Ivar *ivars=class_copyIvarList([Person class], &count);

    //遍历成员变量

    for (int i=0; i<count; i++) {

        Ivar ivar=ivars[i];

        const char *name=ivar_getName(ivar);

        const char *type=ivar_getTypeEncoding(ivar);

        NSLog(@"%s,%s",name,type);

    }

}


输出结果是:



_age,i

_name,@"NSString"


(3)block变量定义时为什么用copy?block是放在哪里的?


——默认情况下,block是存档在栈中,可能被随时回收,需要copy操作。这也就是我们在定义block的时候用得时copy。而不是weak等等。


//默认是放在栈中,可能会被随时销毁

    void (^blockName)()=^{

        

    };

    //进行一次copy操作,就可以放在堆中了。

    //[blockName copy];

    //以下方法也一样。但是只能在非ARC中使用。

    //Block_copy(blockName);

    

    //retain没有用的原因:retain只是增加一次计数,block内存还是在栈中,并没有转移到堆中。


——block如果是copy的话,里面使用它所在的类的对象的话,这个对象永远无法被释放。即person对象在堆中是强指针,且person在blockName就在,而blockName指向的代码也在堆中,即它的person.age=20的那些代码也在堆中,而这些代码中有person对象,所以又反过来指向person对象。就这么在相互指向的,永远不能释放。



    Person *person=[[Person alloc]init];

    person.blockName=^{

        person.age=20;

    };


解决办法如下。此处还不能直接把__unsafe_unretained放在创建person对象的那一行。因为如果那样的话,这个person对象是一个弱指针指向的,一出生就死了。引入弱指针person0的目的就是block代码里的person0回指对象时,是弱引用,这样就不会出现2个强引用互相指着。也可以用__weak。



    Person *person=[[Person alloc]init];

    __unsafe_unretained Person *person0=person;

    person.blockName=^{

        person0.age=20;

    };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值