block为什么用copy?利用runtime运行时的objc_方法为分类扩充成员变量

转载 2016年06月01日 10:15:06


(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;
    };

【iOS开发-117】block为什么用copy?利用runtime运行时的objc_方法为分类扩充成员变量

block为什么用copy?利用runtime运行时的objc_方法为分类扩充成员变量
  • wsb200514
  • wsb200514
  • 2015年01月30日 15:32
  • 1803

Block为什么用copy修饰

默认情况下,block是存档在栈中,可能被随时回收,通过copy操作可以使其在堆中保留一份, 相当于一直强引用着, 因此如果block中用到self时, 需要将其弱化, 通过__weak或者__uns...
  • wangjunling888
  • wangjunling888
  • 2016年05月12日 23:31
  • 5335

block为什么使用copy修饰

block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block...
  • dingyanpeng
  • dingyanpeng
  • 2015年12月16日 12:37
  • 931

Objective-C中为何用copy修饰block

简单来说,block就像一个函数指针,指向我们要使用的函数。 就和函数调用一样的,不管你在哪里写了这个block,只要你把它放在了内存中(通过调用存在这个block的方 法或者是函数),不管放在栈...
  • Cedric_JC
  • Cedric_JC
  • 2015年09月17日 19:31
  • 2729

block为什么用copy

block为什么用copy?  (1)block - (void)viewDidLoad {     [super viewDidLoad];     __block int a=...
  • bravegogo
  • bravegogo
  • 2016年04月11日 23:26
  • 388

iOS block为什么要用copy

//联系人:石虎  QQ: 1224614774昵称:嗡嘛呢叭咪哄 一、栈区和堆区概念 内存的栈区 : 由编译器自动分配释放, 存放函数的参数值, 局部变量的值等. 其操作方式类似于数据结构...
  • shihuboke
  • shihuboke
  • 2017年09月10日 12:10
  • 282

ios中为什么block用copy属性

Block的声明和线程安全 Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC下返...
  • sinat_29379553
  • sinat_29379553
  • 2015年07月04日 17:04
  • 181

Block 为什么要用copy属性

1. Block的声明和线程安全 Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非A...
  • zhanniuniu
  • zhanniuniu
  • 2016年04月04日 23:45
  • 1276

block为什么用copy关键字

ARC 开发的时候,编译器底层对 block 做过一些优化,可以防止出现内存泄漏         myBlock 是保存在栈区的,出了作用域,就应该被销毁         如果用 ...
  • Lee_lisa520
  • Lee_lisa520
  • 2015年08月03日 10:21
  • 131

Runtime消息机制,交换方法,动态添加方法,分类添加属性

Runtime 简称运行时,OC就是运行时机制 // OC:运行时机制,消息机制是运行时机制最重要的机制 // 消息机制:任何方法调用,本质都是发送消息 严格检查运行机制设置为no...
  • qq_30997845
  • qq_30997845
  • 2016年06月13日 11:04
  • 1200
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:block为什么用copy?利用runtime运行时的objc_方法为分类扩充成员变量
举报原因:
原因补充:

(最多只允许输入30个字)