OC基础知识梳理

2021-04-18  本文已影响0人  Space2016

OC语法相关

1、一般什么情况下用分类

2、分类和类扩张的区别

继承关系 BeautyCat -> Cat - > Animal()
类和分类 Animal,Animal+bb,Animal+aa,Cat,Cat+bb,Cat+aa,BeautyCat,BeautyCat+aa
测试结果:
/*------------------------------------------------------*
2021-04-15 11:17:46.141459+0800 cccExtention[40555:7540175] +[Animal load]
2021-04-15 11:17:46.159957+0800 cccExtention[40555:7540175] +[Cat load]
2021-04-15 11:17:46.161076+0800 cccExtention[40555:7540175] +[BeautyCat load]
2021-04-15 11:17:46.161541+0800 cccExtention[40555:7540175] +[BeautyCat(aa) load]
2021-04-15 11:17:46.163238+0800 cccExtention[40555:7540175] +[Animal(aa) load]
2021-04-15 11:17:46.163901+0800 cccExtention[40555:7540175] +[Animal(bb) load]
2021-04-15 11:17:46.164747+0800 cccExtention[40555:7540175] +[Cat(aa) load]
2021-04-15 11:17:46.166138+0800 cccExtention[40555:7540175] +[Cat(bb) load]
2021-04-15 11:17:46.252135+0800 cccExtention[40555:7540175] +[Animal(bb) initialize]
2021-04-15 11:17:46.252318+0800 cccExtention[40555:7540175] +[Cat(bb) initialize]
2021-04-15 11:17:46.253647+0800 cccExtention[40555:7540175] +[BeautyCat(aa) initialize]

疑问

3、关联对象

ObjcAssociation对象 在runtime源码的定义

class ObjcAssociation {
    uintptr_t _policy; // 内存管理策略()
    id _value; // 存储的值
};

policy 可以取的值

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                            *   The association is made atomically. */
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                            *   The association is made atomically. */
};

示例代码

-(void)setVersion:(NSString * _Nonnull)version
{
    objc_setAssociatedObject(self, @selector(version), version, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

-(NSString *)version
{
    NSString *ver = objc_getAssociatedObject(self, _cmd);
    return ver;
}

4、KVO

-(void)setName:(NSString *)name
{
    [self willChangeValueForKey:@"name"];
    [super setName:name]; //原来的setter方法
    [self didChangeValueForKey:@"name"]; // 调用observeValueForKeyPath 方法
}

示例代码

//添加监测网页加载进度的观察者
[self.webView addObserver:self
               forKeyPath:NSStringFromSelector(@selector(estimatedProgress))
                  options:0
                  context:nil];
         
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                      context:(void *)context{
    
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]
        && object == _webView) {
        NSLog(@"网页加载进度 = %f",_webView.estimatedProgress);
        }
}

5、KVC

流程图

KVC.jpeg

6、isa走位图

isa走位图.png

7、 属性关键字有哪些?可以分为几类?

读写相关

引用计数器内存管理相关

线程安全相关

8、objc源码常见的数据结构

isa_t

isa_t 是一个联合体,部分源码如下

union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;

#if SUPPORT_PACKED_ISA
# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
#       define RC_ONE   (1ULL<<45)
#       define RC_HALF  (1ULL<<18)
    };

    };

可以看出isa_t 只有两个数据成员,一个是指针类型Class cls,一个是unsigned long类型uintptr_t bits,所以整个联合体的内存只有64位。

objc_object 结构体

struct objc_object {
private:
    isa_t isa;
public:
    .....
}

可以看到objc_object在源码中只有一个私有成员变量isa,类型是isa_t,这个结构类型是一个联合体,里面只包含64位数据,但是会根据不同的情况,64位数据表示方式有所区别。
接下来就是这个结构体提供给外部使用的方法

//部分objc_object 结构体中的方法如下
//初始化方法
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);

//isa 类型判断方法
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();

//内存管理相关方法
id retain();
void release();
id autorelease();

Class 类型

Class 类型在runtime源码定义为

typedef struct objc_class *Class;

objc_class 结构体

objc_class 继承自 objc_object,在runtime的部分代码如下

// objc_class继承于objc_object,因此
// objc_class中也有isa结构体
struct objc_class : objc_object {
    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() {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
    ......
    bool isARC() {
        return data()->ro->flags & RO_IS_ARC;
    }
    ......
}

objc_class 结构体其实就是我们平时所说的类对象,有指向父类的isa指针(superclass),有方法缓存cache_t,有类的方法,属性,协议(保存在class_rw_t中)等信息。

cache_t 结构体

先看看cache_t 结构体的源码

struct cache_t {
    struct bucket_t *_buckets; //散列表
    mask_t _mask;   //散列表的长度 -1
    mask_t _occupied; //已经缓存的数量
    ......
    
}

bucket_t 在arm64的定义为

struct bucket_t {
private:
    // IMP-first is better for arm64e ptrauth and no worse for arm64.
    // SEL-first is better for armv7* and i386 and x86_64.
#if __arm64__
    MethodCacheIMP _imp;
    cache_key_t _key;
#else

可以看到cache_t 是利用散列表来缓存bucket_t对象,而bucket_t保存了缓存key和方法调用的 IMP指针

class_data_bits_t 结构体

struct class_data_bits_t {

    // Values are the FAST_ flags above.
    uintptr_t bits;
    ......
}

class_rw_t 结构体

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    // 方法信息
    method_array_t methods;
    // 属性信息
    property_array_t properties;
    // 协议信息
    protocol_array_t protocols;
    ......
}

可以看到class_rw_t 结构体的rw(readwrite)表示可读写的意思,这里保存了类的方法,属性,协议等信息,class_ro_t 结构体也保存了以上信息,但是他是不可读写的(ro,readonly),所以在运行时会把分类的方法,协议等信息动态添加到这里。

method_t 结构体

struct method_t {
    SEL name;
    const char *types;
    MethodListIMP imp;
    struct SortBySELAddress :
        public std::binary_function<const method_t&,
                                    const method_t&, bool>
    {
        bool operator() (const method_t& lhs,
                         const method_t& rhs)
        { return lhs.name < rhs.name; }
    };
};

method_t 有三个成员变量

property_t结构体

struct property_t {
    const char *name;
    const char *attributes;
};

9、@dynamic和@synthesize

这两个关键字都是和@property 相关的,如果这两个关键字都没有写,只写了@property来声明属性,那么默认就是@synthesize var = _var;
如果添加了@dynamic 关键字,那么就是告诉编译器自己手动生成setter和getter方法(如果是readonly就只需生成getter),如何你没有生动生成,那么运行时就不会报错。

额外:
.m文件反编译cpp文件的指令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

UI相关

1、UIView和CALayer的关系

持续更新ing

上一篇下一篇

猜你喜欢

热点阅读