一、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
}
Ivar
是objc_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_setIvar
和object_setIvarWithStrongDefault
,这两个函数都和内存管理有关系。先说下它们的共同点,如果内存管理属于已知的内存管理方式(成员变量或属性属于ARC
,strong
或者weak
),它们都没有区别。不同点就是如果是属于未知的内存管理方式,object_setIvar
会把该实例变量被分配为unsafe_unretain
,而object_setIvarWithStrongDefault
会把该实例变量被分配为strong
。 首先我们要清楚3个概念,strong
,weak
和unsafe_unretain
。 strong
是强引用指向并拥有那个对象,根据retainCount
是否为0来确定是否释放内存 weak
是弱引用指向但并不拥有那个对象。释放空间时会自动将指针设置成nil
。 unsafe_unretain
和weak
类似,只是释放空间时不会将指针设置成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);//哈哈