前言
类实例话的属性变量 以及实例方法 以及协议的类方法 实例方法 属性 通过上一篇已经已经找到了 如何找到类方法和成员变量 我们这节继续搞一搞
一.如何找到成员变量
(lldb) p/x LGPerson.class //打印LGPerson类地址
(Class) $0 = 0x00000001000088b0 LGPerson
(lldb) x/4gx 0x00000001000088b0 //打印内存地址
0x1000088b0: 0x00000001000088d8 0x000000010036a140
0x1000088c0: 0x00000001012296a0 0x0002804000000003
(lldb) p/x (class_data_bits_t *) 0x1000088d0 //通过0x1000088b0平移32位得到0x1000088d0 获取 class_data_bits_t
(class_data_bits_t *) $1 = 0x00000001000088d0
(lldb) p $1->data() //获取 class_rw_t
(class_rw_t *) $2 = 0x0000000101229640
(lldb) p $2->ro() //获取 class_ro_t
(const class_ro_t *) $3 = 0x00000001000081a8
(lldb) p $3-> ivars//获取ivar_list_t
(const ivar_list_t *const) $4 = 0x00000001000082d0
(lldb)p *$4 //打印$4内容
(const ivar_list_t) $5 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 6)
}
//打印成员变量
(lldb) p $5.get(0)
(ivar_t) $6 = {
offset = 0x00000001000087e0
name = 0x0000000100003d28 "subject"
type = 0x0000000100003e7a "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $5.get(1)
(ivar_t) $7 = {
offset = 0x00000001000087e8
name = 0x0000000100003d30 "array"
type = 0x0000000100003e86 "@\"NSArray\""
alignment_raw = 3
size = 8
}
(lldb) p $5.get(2)
(ivar_t) $8 = {
offset = 0x00000001000087f0
name = 0x0000000100003d36 "dic"
type = 0x0000000100003e91 "@\"NSDictionary\""
alignment_raw = 3
size = 8
}
(lldb) p $5.get(3)
(ivar_t) $9 = {
offset = 0x00000001000087f8
name = 0x0000000100003d3a "_age"
type = 0x0000000100003ea1 "i"
alignment_raw = 2
size = 4
}
(lldb) p $5.get(4)
(ivar_t) $10 = {
offset = 0x0000000100008800
name = 0x0000000100003d3f "_name"
type = 0x0000000100003e7a "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $5.get(5)
(ivar_t) $11 = {
offset = 0x0000000100008808
name = 0x0000000100003d45 "_hobby"
type = 0x0000000100003e7a "@\"NSString\""
alignment_raw = 3
size = 8
}
如上所示 我们
LLDB打印的成员变量里面包含属性 下面我们探究一下为什么
二.成员变量和属性
1.进入终端 执行
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc LGPerson.m -o LGPerson.cpp
2.objc_setProperty和内存平移有什么区别
setName setAge -> objc_setProperty(中间封装) ->LLVM底层代码
我们查看一下LLVM源码 查找objc_setProperty
通过
LLVM分析 copy会执行objc_setProperty 下面用个例子
得出结果
都是
copy 为什么有的有objc_getProperty 有的是内存平移呢 是否根atomic有关系呢
必须是
atomic copy 才会创建objc_getProperty
3.编码
例子: @16@0:8
@ id类型
16 占用的内存
@ id类型(函数的隐士参数self)
0 从0号位置开始
: SEL
8 从8号位置开始
对应的这些编码苹果都有,地址是(developer.apple.com/library/arc…)
三.如何找到类方法
1.为什么要有元类 存储类方法
(lldb) p/x object_getClass(LGPerson.class) //获取元类地址
(Class) $0 = 0x00000001000088d8
(lldb) p (class_data_bits_t *) 0x00000001000088f8 //平移动32位 获取class_data_bits_t
(class_data_bits_t *) $1 = 0x00000001000088f8
(lldb) p $1->data() //获取class_rw_t
(class_rw_t *) $2 = 0x0000000101e125d0
(lldb) p $2.methods()//获取methods
(const method_array_t) $3 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100008798
}
arrayAndFlag = 4295002008
}
}
}
Fix-it applied, fixed expression was:
$2->methods()
(lldb) p $3.list.ptr
(method_list_t *const) $4 = 0x0000000100008798
(lldb) p *$4
(method_list_t) $5 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 1)
}
(lldb) p $5.get(0).big()
(method_t::big) $7 = {
name = "say666"
types = 0x0000000100003e72 "v16@0:8"
imp = 0x0000000100003bc0 (KCObjcBuild`+[LGPerson say666])
}
结论:对象方法在类中 类方法在元类中
1.第一种验证方式
//获取LGPerson类中所有的方法
void lgObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//获取方法名
NSString *key = NSStringFromSelector(method_getName(method));
LGLog(@"Method, name: %@", key);
}
free(methods);
}
创建对象调用上面方法
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);//LGPerson类
lgObjc_copyMethodList(pClass);
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);//LGPerson元类
NSLog(@"*************");
lgObjc_copyMethodList(metaClass);
打印显示结果 表示上面的结论正确
Method, name: sayHello
Method, name: name
Method, name: .cxx_destruct
Method, name: setName:
Method, name: obj
Method, name: setObj:
*************
Method, name: sayHappy
2.第二种验证方式
void lgInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);//元类
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));//验证类里面是否有sayHello 有的
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));//验证元类里面是否有sayHello 无
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));//验证类里面是否有sayHappy 无
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));//验证元类里面是否有sayHappy 有
LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
调用
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);//LGPerson类
lgInstanceMethod_classToMetaclass(pClass);
打印得出结果
lgInstanceMethod_classToMetaclass - 0x1000081c0-0x0-0x0-0x100008158
3.第三种验证方式
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
// - (void)sayHello;
// + (void)sayHappy;
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
调用
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);//LGPerson类lgClassMethod_classToMetaclass(pClass);
打印得出结果
lgClassMethod_classToMetaclass-0x0-0x0-0x100008158-0x100008158
为什么元类类面有sayHappy方法
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));//验证元类里面是否有sayHappy
元类-》class_getInstanceMethod对象方法sayHappy
在底层没有类方法 所有的都是对象方法
4.第四种验证方式
void lgIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));// 0
// sel -> imp 方法的查找流程 imp_farw
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy)); // 0
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
调用
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);//LGPerson类
lgIMP_classToMetaclass(pClass);
打印结果
0x100003ad0-0x7fff2046bac0-0x7fff2046bac0-0x100003b10
}
补充
p *($6+1)等同于p * $7 内存偏移
struct class_data_bits_t { friend objc_class }
friend:objc里面的私有方法都可以使用
对象的isa&ISA_MASK得到类的isa (对象isa 和 类不一样)
类的isa &ISA_MASK得到是元类的isa (类isa 和 元类一样)