iOS Runtime《四》Ivar

一、Ivar可以理解为类中的一个变量,主要作用是用来保存数据的。

1、Ivar 的类型

typedef struct objc_ivar *Ivar;
struct objc_ivar {
    char * _Nullable ivar_name                               OBJC2_UNAVAILABLE;
    char * _Nullable ivar_type                               OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}  

Ivarobjc_ivar的指针,包含变量名,变量类型等成员。

二、常用的方法

1、获取Ivar的名称

OBJC_EXPORT const char * _Nullable
ivar_getName(Ivar _Nonnull v) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

2、获取Ivar的成员类型编码

OBJC_EXPORT const char * _Nullable
ivar_getTypeEncoding(Ivar _Nonnull v) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

3、获取Ivar变量 

//方法一
OBJC_EXPORT Ivar _Nullable
class_getInstanceVariable(Class _Nullable cls, const char * _Nonnull name)
    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);

//方法二
OBJC_EXPORT Ivar _Nullable
class_getClassVariable(Class _Nullable cls, const char * _Nonnull name) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

由于在OC语法里面,并不存在类变量这个概念,所以,这个方法并没有什么用。

例:

新建一个Student类,添加一个成员变量 int _age 和一个属性@property(nonatomic,copy)NSString* name,众所周知,属性会自动生成一个前面带_的成员变量(name生成_name)。

Student.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Student : NSObject
{
    int _age;
}

@property (nonatomic,copy)NSString * name;


@end

NS_ASSUME_NONNULL_END

使用的地方:

 Ivar ageIvar=class_getInstanceVariable(objc_getClass("Student"), "_age");
    
    Ivar nameIvar=class_getInstanceVariable(objc_getClass("Student"), "_name");
    
    [self logIvarName:ageIvar];//name=_age  成员变量的类型=i 
    [self logIvarName:nameIvar]; //name=_name  成员变量的类型=@"NSString" 


-(void)logIvarName:(Ivar)ivar
{
    if (ivar) {
        
        //成员变量的名字
        const  char *name=ivar_getName(ivar);
         //成员变量的类型
        const char *type=ivar_getTypeEncoding(ivar);
        NSLog(@"name=%s  成员变量的类型=%s ",name,type);
        
    }
    else{
        NSLog(@"ivar为null");
    }
}

---------------------------------------------------------------------------------------------------------

4、获取一个类的所有成员变量

OBJC_EXPORT Ivar _Nonnull * _Nullable
class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

outCount:参数为成员变量的总数量

.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Student : NSObject
{
    int _age;
}

@property (nonatomic,copy)NSString * name;
@property (nonatomic,assign)NSInteger height;
@property (nonatomic,assign)BOOL sex;

@end

NS_ASSUME_NONNULL_END
// 获取一个类的所在成员变量
    unsigned int count;
    
    Ivar *ivars=class_copyIvarList(objc_getClass("Student"), &count);
    NSLog(@"总个数: = %d",count);
    
    for (int i=0; i<count; i++) {
        Ivar ivar=ivars[i];
        [self logIvarName:ivar];
    }
2019-03-29 16:15:38.723694+0800 Ivar[13801:2850782] 总个数: = 4
2019-03-29 16:15:38.723954+0800 Ivar[13801:2850782] name=_age  成员变量的类型=i 
2019-03-29 16:15:38.724099+0800 Ivar[13801:2850782] name=_sex  成员变量的类型=B 
2019-03-29 16:15:38.724234+0800 Ivar[13801:2850782] name=_name  成员变量的类型=@"NSString" 
2019-03-29 16:15:38.724365+0800 Ivar[13801:2850782] name=_height  成员变量的类型=q 

5、ivar赋值与取值

// 1、取值
OBJC_EXPORT id _Nullable
object_getIvar(id _Nullable obj, Ivar _Nonnull ivar) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
// 2、赋值
OBJC_EXPORT void
object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

// 3、赋值
OBJC_EXPORT void
object_setIvarWithStrongDefault(id _Nullable obj, Ivar _Nonnull ivar,
                                id _Nullable value) 
    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);

object_setIvarobject_setIvarWithStrongDefault,这两个函数都和内存管理有关系。先说下它们的共同点,如果内存管理属于已知的内存管理方式(成员变量或属性属于ARCstrong或者weak),它们都没有区别。不同点就是如果是属于未知的内存管理方式,object_setIvar会把该实例变量被分配为unsafe_unretain,而object_setIvarWithStrongDefault会把该实例变量被分配为strong。 首先我们要清楚3个概念,strong,weakunsafe_unretainstrong是强引用指向并拥有那个对象,根据retainCount是否为0来确定是否释放内存 weak是弱引用指向但并不拥有那个对象。释放空间时会自动将指针设置成nilunsafe_unretainweak类似,只是释放空间时不会将指针设置成nil,所以会有野指针的危害。 所以,在ARC下,这两个方法的作用几乎一模一样。

例: 

    Student *stu=[[Student alloc]init];
    Ivar nameIvar=class_getInstanceVariable(objc_getClass("Student"), "_name");
    //赋值
    object_setIvar(stu, nameIvar, @"哈哈");
    //取值
    NSString *name=object_getIvar(stu, nameIvar);
    NSLog(@"%@",name);//哈哈

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值