iOS-底层原理04-类原理&方法&属性

《iOS底层原理文章汇总》

类分析

1.获取对象的isa,得到类信息

(lldb) x/4gx person
0x1007041a0: 0x001d8001000021a9 0x0000000000000000
0x1007041b0: 0x00007fff8a1bc860 0x000000010063ec10
(lldb) p/x 0x001d8001000021a9 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x00000001000021a8
(lldb) po 0x00000001000021a8
DCPerson

I. 查看类的地址,类有关于类的内存分布

1.通过打印isa

(lldb) x 0x00000001000021a8
0x1000021a8: 80 21 00 00 01 00 00 00 40 61 33 00 01 00 00 00  .!......@a3.....
0x1000021b8: d0 03 33 00 01 00 00 00 00 00 00 00 10 80 00 00  ..3.............

2.通过打印类.class

(lldb) x DCPerson.class
0x1000021a8: 80 21 00 00 01 00 00 00 40 61 33 00 01 00 00 00  .!......@a3.....
0x1000021b8: d0 03 33 00 01 00 00 00 00 00 00 00 10 80 00 00  ..3.............

3.通过runtime底层api打印object_getClass(对象)

(lldb) x object_getClass(person)
0x1000021a8: 80 21 00 00 01 00 00 00 40 61 33 00 01 00 00 00  .!......@a3.....
0x1000021b8: d0 03 33 00 01 00 00 00 00 00 00 00 10 80 00 00  ..3.............

II. 查看isa的关于类的内存地址的内存分布,与上MASK和不与上MASK的值是一样的,最后得到的首地址的值还为isa指针,指向类

(lldb) x/4gx 0x00000001000021a8
0x1000021a8: 0x0000000100002180 0x0000000100336140
0x1000021b8: 0x00000001003303d0 0x0000801000000000

(lldb) po 0x0000000100002180
DCPerson

(lldb) p/x 0x0000000100002180 & 0x00007ffffffffff8ULL
(unsigned long long) $6 = 0x0000000100002180
(lldb) po 0x0000000100002180
DCPerson

两个内存地址的值(0x00000001000021a8和0x0000000100002180)都是DCPerson???这是为什么呢,到底哪一个是DCPerson呢???

于是就有元类的概念--系统提供元类,对象-isa-类(对象)->元类,接下来会有方法,协议,属性的归属,元类的定义和创建都是由编译器自动完成,类方法存储在元类里面

  • 1.查看元类的内存信息
(lldb) x/4gx DCPerson.class
0x1000021a8: 0x0000000100002180 0x0000000100336140
0x1000021b8: 0x00000001003303d0 0x0000801000000000
(lldb) p/x 0x0000000100002180 & 0x00007ffffffffff8ULL
(unsigned long long) $9 = 0x0000000100002180
(lldb) x/4gx 0x0000000100002180
0x100002180: 0x00000001003360f0 0x00000001003360f0
0x100002190: 0x0000000100706a90 0x0004e03100000007
  • 2.再往下查看根元类的内存信息
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $10 = 0x00000001003360f0
(lldb) x/4gx 0x00000001003360f0
0x1003360f0: 0x00000001003360f0 0x0000000100336140
0x100336100: 0x0000000100782b30 0x0004e03100000007
(lldb) po 0x00000001003360f0
NSObject

和本身的系统的NSObject.class不是同一个

(lldb) po 0x00000001003360f0
NSObject

(lldb) po NSObject.class
NSObject

(lldb) p/x NSObject.class
(Class) $13 = 0x0000000100336140 NSObject

面试题:NSObject类存在几份,类的信息在内存中永远只存在一份

isa 对象 -> 类(DCPerson) -> 元类(DCPerson) -> NSObject(根元类) -> NSObject(根元类)

  • 3.分析类对象内存存在个数
void lgTestClassNum(){
    Class class1 = [DCPerson class];
    Class class2 = [DCPerson alloc].class;
    Class class3 = object_getClass([DCPerson alloc]);
    Class class4 = [DCPerson alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}
0x1000020f0-
0x1000020f0-
0x1000020f0-
0x1000020f0
  • 4.上面得出的不是NSObject的类,而是NSObject的元类,也叫根元类,地址0x00000001003360f0是一样的。验证如下:
根元类@2x.png
(lldb) po 0x00000001003360f0
NSObject

(lldb) po NSObject.class
NSObject

(lldb) p/x NSObject.class
(Class) $13 = 0x0000000100336140 NSObject
(lldb) x/4gx 0x0000000100336140
0x100336140: 0x00000001003360f0 0x0000000000000000
0x100336150: 0x000000010067fae0 0x0001801000000003
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $14 = 0x00000001003360f0
(lldb) po 0x00000001003360f0
NSObject
  • 5.继续往下探究:查看根元类的isa指向的类的内存信息
(lldb) x/4gx DCPerson.class
0x1000021a8: 0x0000000100002180 0x0000000100336140
0x1000021b8: 0x00000001003303d0 0x0000801000000000
(lldb) p/x 0x0000000100002180 & 0x00007ffffffffff8ULL
(unsigned long long) $9 = 0x0000000100002180
(lldb) x/4gx 0x0000000100002180
0x100002180: 0x00000001003360f0 0x00000001003360f0
0x100002190: 0x0000000100706a90 0x0004e03100000007
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $10 = 0x00000001003360f0
(lldb) x/4gx 0x00000001003360f0
0x1003360f0: 0x00000001003360f0 0x0000000100336140
0x100336100: 0x0000000100782b30 0x0004e03100000007
(lldb) po 0x00000001003360f0
NSObject

(lldb) po NSObject.class
NSObject

(lldb) p/x NSObject.class
(Class) $13 = 0x0000000100336140 NSObject
(lldb) x/4gx 0x0000000100336140
0x100336140: 0x00000001003360f0 0x0000000000000000
0x100336150: 0x000000010067fae0 0x0001801000000003
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $14 = 0x00000001003360f0
(lldb) po 0x00000001003360f0
NSObject

(lldb) x/4gx 0x00000001003360f0
0x1003360f0: 0x00000001003360f0 0x0000000100336140
0x100336100: 0x0000000100782b30 0x0005e03100000007
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $16 = 0x00000001003360f0
(lldb) po 0x00000001003360f0
NSObject

(lldb) x/4gx 0x00000001003360f0
0x1003360f0: 0x00000001003360f0 0x0000000100336140
0x100336100: 0x0000000100782b30 0x0005e03100000007
(lldb) p/x 0x00000001003360f0 & 0x00007ffffffffff8ULL
(unsigned long long) $18 = 0x00000001003360f0
(lldb) po 0x00000001003360f0
NSObject
根元类指向根元类@2x.png

isa指向关系

只有NSObject少了一步元类的指向


isa指向图@2x.png
void lgTestNSObject(){
    //NSObject实例对象
    NSObject *object1 = [NSObject alloc];
    //NSObject类
    Class class = object_getClass(object1);
    //NSObject元类
    Class metaClass = object_getClass(class);
    //NSObject根元类
    Class rootMetaClass = object_getClass(metaClass);
    //NSObject根根元类
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);;
}
0x100479120 实例对象
0x7fff92977118 类
0x7fff929770f0 元类
0x7fff929770f0 根元类
0x7fff929770f0 根根元类
  • 6.实例对象之间根本没有任何关系,即没有继承关系,继承关系来自于类,只有类才有继承关系,根元类指向NSObject
    DCTeacher(儿子) --> DCPerson(父亲) --> NSObject --> (isa) nil 0-1
    teacher继承于person,查看person和teacher的实例对象,类,元类,根元类的内存地址


    isa流程图.png
void lgInherit(){
    //DCPerson实例对象
    DCPerson *person = [DCPerson alloc];
    //DCPerson类
    Class personClass = object_getClass(person);
    //DCPerson元类
    Class personMetaClass = object_getClass(personClass);
    //DCPerson根元类
    Class personRootMetaClass = object_getClass(personMetaClass);
    //DCPerson根根元类
    Class personRootRootMetaClass = object_getClass(personRootMetaClass);
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类\n",person,personClass,personMetaClass,personRootMetaClass,personRootRootMetaClass);
    
    //DCTeacher实例对象
    DCPerson *teacher = [DCTeacher alloc];
    //DCTeacher类
    Class teacherClass = object_getClass(teacher);
    //DCTeacher元类
    Class teacherMetaClass = object_getClass(teacherClass);
    //DCTeacher根元类
    Class teacherRootMetaClass = object_getClass(teacherMetaClass);
    //DCTeacher根根元类
    Class teacherRootRootMetaClass = object_getClass(teacherRootMetaClass);
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",teacher,teacherClass,teacherMetaClass,teacherRootMetaClass,teacherRootRootMetaClass);
}
2020-10-04 15:33:51.316625+0800 iOS-isa分析[46409:2533244] 
0x10040aea0 实例对象
0x100002198 类
0x100002170 元类
0x7fff929770f0 根元类
0x7fff929770f0 根根元类

2020-10-04 15:33:51.316711+0800 iOS-isa分析[46409:2533244] 
0x100704c40 实例对象
0x1000021e8 类
0x1000021c0 元类
0x7fff929770f0 根元类
0x7fff929770f0 根根元类

通过clang编译成C++文件发现,对象和类的底层都是结构体,objc_object(根对象) vs object_class(Class) (NSObject) (isa)

NSObject类 VS 对象: struct objc_class:objc_object

对象 + 类 + 元类 都有isa,objc_object对象的关系,NSObject(OC),objc_object(C/C++)结构体,

struct objc_class *Class定义一个Class()


objc_object@2x.png

类的内存分布(p/x--p为打印,x为以十六进制打印当前内存信息)

  • 1.查看类的内存信息
(lldb) x/4gx DCPerson.class
0x1000021a8: 0x0000000100002180 0x0000000100336140
0x1000021b8: 0x00000001003303d0 0x0000801000000000
(lldb) po 0x0000000100336140
NSObject

(lldb) p/x NSObject.class
(Class) $23 = 0x0000000100336140 NSObject
(lldb) 父类为NSObject
  • 2.查看类信息的源码
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }

    void clearInfo(uint32_t clear) {
        ASSERT(isFuture()  ||  isRealized());
        data()->clearFlags(clear);
    }
}
8.gif

object_class@2x.png

类的methodlist,propertylist,ivarlist在哪儿???

C语言中的内存平移

  • 1.通过内存地址平移获取数组中的值
        //普通指针
        int a = 10;
        int b = 10;
        DCNSLog(@"%d -- %p",a,&a);
        DCNSLog(@"%d -- %p",b,&b);
        
        //对象
        DCPerson *p1 = [DCPerson alloc];
        DCPerson *p2 = [DCPerson alloc];
        DCNSLog(@"%@ -- %p",p1,&p1);
        DCNSLog(@"%@ -- %p",p2,&p2);
        
        //数组指针
        int c[4] = {1,2,3,4};
        int * p = c;
        for (int i = 0; i<4; i++) {
            int value = c[i];
            int v = *(p+i);
            DCNSLog(@"%d",value);
            DCNSLog(@"%d",v);
        }
        NSLog(@"指针-内存偏移");
//输出
10 -- 0x7ffeefbff42c
10 -- 0x7ffeefbff428
<DCPerson: 0x100566bd0> -- 0x7ffeefbff420
<DCPerson: 0x100565c90> -- 0x7ffeefbff418
0x7ffeefbff440,0x7ffeefbff440,0x7ffeefbff440,0x7ffeefbff444,0x7ffeefbff448,0x7ffeefbff44c
1
1
2
2
3
3
4
4
2020-10-04 19:06:42.214800+0800 iOS-内存偏移[59476:2804871] 指针-内存偏移

DCPerson.class地址 - 平移 拿到所有的值

怎么获取objc_class中的cache和bits的值呢???

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }
}
类中的属性@2x.png

objc_class内存分布@2x.png
  • 1.如果要知道bits的值,得先知道bits结构体属性ISA指针的大小(8字节),superclass的大小(8字节),cache的大小(未知),进行平移

I 查看cache的大小

struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
    
    // How much the mask is shifted by.
    static constexpr uintptr_t maskShift = 48;
    
    // Additional bits after the mask which must be zero. msgSend
    // takes advantage of these additional bits to construct the value
    // `mask << 4` from `_maskAndBuckets` in a single instruction.
    static constexpr uintptr_t maskZeroBits = 4;
    
    // The largest mask value we can store.
    static constexpr uintptr_t maxMask = ((uintptr_t)1 << (64 - maskShift)) - 1;
    
    // The mask applied to `_maskAndBuckets` to retrieve the buckets pointer.
    static constexpr uintptr_t bucketsMask = ((uintptr_t)1 << (maskShift - maskZeroBits)) - 1;
    
    // Ensure we have enough bits for the buckets pointer.
    static_assert(bucketsMask >= MACH_VM_MAX_ADDRESS, "Bucket field doesn't have enough bits for arbitrary pointers.");
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    // _maskAndBuckets stores the mask shift in the low 4 bits, and
    // the buckets pointer in the remainder of the value. The mask
    // shift is the value where (0xffff >> shift) produces the correct
    // mask. This is equal to 16 - log2(cache_size).
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;

    static constexpr uintptr_t maskBits = 4;
    static constexpr uintptr_t maskMask = (1 << maskBits) - 1;
    static constexpr uintptr_t bucketsMask = ~maskMask;
#else
#error Unknown cache mask storage type.
#endif
    
#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;
}

explicit_atomic<struct bucket_t *> _buckets; 泛型为结构体指针,8字节

explicit_atomic<mask_t> _mask; mask_t为typedef uint32_t mask_t;为typedef unsigned int uint32_t;4字节

uint16_t _flags; typedef unsigned short uint16_t;2字节

uint16_t _occupied; 2字节

综上cache的大小8+4+2+2=16字节

要获取bits首地址需要平移ISA(8字节)+superclass(8字节)+cache(16) = 32字节,具体为首地址0x1000021b0平移32位得到0x1000021d0

获取class_data_bits_t bits的值:打印出firstSubclass为DCTeacher

DCPerson was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) x/4gx DCPerson.class
0x1000021b0: 0x0000000100002188 0x0000000100336140
0x1000021c0: 0x00000001003303d0 0x0000801000000000
(lldb) p (class_data_bits_t *)0x1000021d0
(class_data_bits_t *) $1 = 0x00000001000021d0
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000101928700
(lldb) p *$2
(class_rw_t) $3 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975624
  }
  firstSubclass = DCTeacher
  nextSiblingClass = NSUUID
}
9.gif

往里探究ro_or_rw_ext

(lldb) p $3.ro_or_rw_ext
(explicit_atomic<unsigned long>) $4 = {
  std::__1::atomic<unsigned long> = 4294975624
}
  • 1.查看class_rw_t源码
struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif

    explicit_atomic<uintptr_t> ro_or_rw_ext;

    Class firstSubclass;
    Class nextSiblingClass;

private:
    using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;

    const ro_or_rw_ext_t get_ro_or_rwe() const {
        return ro_or_rw_ext_t{ro_or_rw_ext};
    }

    void set_ro_or_rwe(const class_ro_t *ro) {
        ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);
    }

    void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
        // the release barrier is so that the class_rw_ext_t::ro initialization
        // is visible to lockless readers
        rwe->ro = ro;
        ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
    }

    class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);

public:
    void setFlags(uint32_t set)
    {
        __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
    }

    void clearFlags(uint32_t clear) 
    {
        __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
    }

    // set and clear must not overlap
    void changeFlags(uint32_t set, uint32_t clear) 
    {
        ASSERT((set & clear) == 0);

        uint32_t oldf, newf;
        do {
            oldf = flags;
            newf = (oldf | set) & ~clear;
        } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
    }

    class_rw_ext_t *ext() const {
        return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
    }

    class_rw_ext_t *extAllocIfNeeded() {
        auto v = get_ro_or_rwe();
        if (fastpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
        } else {
            return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
        }
    }

    class_rw_ext_t *deepCopy(const class_ro_t *ro) {
        return extAlloc(ro, true);
    }

    const class_ro_t *ro() const {
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
        }
        return v.get<const class_ro_t *>(&ro_or_rw_ext);
    }

    void set_ro(const class_ro_t *ro) {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
        } else {
            set_ro_or_rwe(ro);
        }
    }

    const method_array_t methods() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
        }
    }

    const property_array_t properties() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
        }
    }

    const protocol_array_t protocols() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
        }
    }
};

类中添加一个属性一个成员变量,一个实例方法和一个类方法

@interface DCPerson : NSObject{
    NSString *hobby;
}
@property(nonatomic,copy)NSString *kc_name;
-(void)sayNB;
+(void)say666;
@end
  • 2.属性的值:有一个属性kc_name,和一个成员变量的hobby,目前只能打印kc_name的值
(lldb) x/4gx DCPerson.class
0x1000022c0: 0x0000000100002298 0x0000000100336140
0x1000022d0: 0x00000001003303d0 0x0000802400000000
(lldb) p (class_data_bits_t *)0x1000022e0
(class_data_bits_t *) $1 = 0x00000001000022e0
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100678680
(lldb) p $2->properties()
(const property_array_t) $3 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x00000001000021b8
      }
      arrayAndFlag = 4294975928
    }
  }
}
(lldb) p $3.list.ptr
(property_list_t *const) $4 = 0x00000001000021b8
(lldb) p *$4
(property_list_t) $5 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 1)
}
(lldb) p $5.get(0)
(property_t) $6 = (name = "kc_name", attributes = "T@\"NSString\",C,N,V_kc_name")
(lldb) p $5.get(1)
Assertion failed: (i < count), function get, file /Users/cloud/Documents/iOS/0911/0911练习/iOS-isa指针/runtime/objc-runtime-new.h, line 479.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.

count = 1为1表示仅有1个属性kc_name


10.gif
  • 3.方法的值:count = 4,表明有4个方法,sayNB,属性的setter和getter方法,kc_name,setKc_name:,.cxx_destruct,C++位于OC底层,默认会自动添加方法,都是实例方法,并没有类方法say666()。
(lldb) p/x DCPerson.class
(Class) $0 = 0x00000001000022c0 DCPerson
(lldb) p (class_data_bits_t *)0x00000001000022e0
(class_data_bits_t *) $1 = 0x00000001000022e0
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010089e5f0
(lldb) p *$2
(class_rw_t) $3 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975680
  }
  firstSubclass = DCTeacher
  nextSiblingClass = NSUUID
}
(lldb) p $3.methods()
(const method_array_t) $4 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x0000000100002108
      }
      arrayAndFlag = 4294975752
    }
  }
}
(lldb) p $4.list.ptr
(method_list_t *const) $5 = 0x0000000100002108
(lldb) p *$5
(method_list_t) $6 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 26, count = 4)
}
(lldb) p $6.get(0)
(method_t) $7 = {}
(lldb) p $7.name()
(SEL) $8 = "sayNB"
(lldb) p $7.types()
(const char *) $9 = 0x0000000100000f7c "v16@0:8"
(lldb) p $6.get(1)
(method_t) $10 = {}
(lldb) p $10.name()
(SEL) $11 = "kc_name"
(lldb) p $10.types()
(const char *) $12 = 0x0000000100000f90 "@16@0:8"
(lldb) p $6.get(2)
(method_t) $13 = {}
(lldb) p $13.name()
(SEL) $14 = "setKc_name:"
(lldb) p $13.types()
(const char *) $15 = 0x0000000100000f98 "v24@0:8@16"
(lldb) p $6.get(3)
(method_t) $16 = {}
(lldb) p $16.name()
(SEL) $17 = ".cxx_destruct"
(lldb) p $16.types()
(const char *) $18 = 0x0000000100000f7c "v16@0:8"
(lldb) p $6.get(4)
Assertion failed: (i < count), function get, file /Users/cloud/Documents/iOS/0911/0911练习/iOS-isa指针/runtime/objc-runtime-new.h, line 479.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
11.gif

那成员变量和类方法在哪里查看呢???

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容