OC基础知识点梳理

2021-05-26  本文已影响0人  Hao_Orz

属性关键字

1. 属性关键字都有哪些?

2. 使用atomic一定是线程安全的吗?

当一个对象被atomic关键字修饰,系统会在生成的setter/getter方法里添加锁,保证了读写时的安全,但并不能保证线程安全。

3. assign和weak的区别

assign关键字的特点:

weak关键字的特点

weak关键字只能修饰对象;而assign既可以修饰对象,也可以修饰基本数据类型。
assign修饰的对象在被释放之后,指针仍指向原对象地址;而weak所指对象在被释放之后会自动置为nil。

4. 浅拷贝和深拷贝

浅拷贝
浅拷贝就是对内存地址的复制,让目标对象指针和原对象指向同一片内存空间。

深拷贝
深拷贝让目标对象指针和原对象指针指向两片内容相同的内存空间。

copy关键字

源对象类型 拷贝方式 目标对象类型 拷贝类型
mutable对象 copy 不可变 深拷贝
mutable对象 mutableCopy 可变 深拷贝
immutable对象 copy 不可变 浅拷贝
immutable对象 mutableCopy 可变 深拷贝

5. MRC下如何重写retain修饰变量的setter方法?

@property (nonatomic, retain) id obj;

- (void)setObj:(id)obj {
    if (_obj != obj) {
        // 判断不是同一个对象再release,防止异常处理
        [_obj release];
        _obj = [obj retain];
    }
}

分类

1. 你用分类都做了哪些事?

2. 分类的特点:

3. 分类中都可以添加哪些内容?

注:在分类中定义的属性,实际上只生成了对应的get和set方法,并没有在分类中添加实例变量。但分类可以通过关联对象的方法来添加实例变量。

4. 分类的结构体

struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protpcpl_list_t *protocols;
    struct property_list_t *instanceProperties;
    
    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }
    
    protpcpl_list_t *propertiesForMeta(bool isMeta) {
        if (isMeta) return nil; // classProperties;
        else retuen instanceProperties;
    }
};

5. 多个分类包含同名方法时,会怎么样?

关联对象

1. 关联对象的本质

关联对象由AssociationsManager管理并在AssociationsHashMap存储。
所有对象的关联内容都在同一个全局容器中。

通过关联对象技术为分类添加的成员变量,并没有添加到分类所对应的宿主类上。

扩展

1. 一般用扩展做什么?

2. 扩展的特点

3. 分类和扩展的区别

  1. 分类是运行时决议,扩展是编译时决议。
  2. 分类可以有声明和实现,而扩展只有声明没有实现
  3. 可以为系统类添加分类,但不能为系统类添加扩展

通知和代理

1. 通知的特点

2. 代理的特点

3. 代理为什么以weak形式声明?

往往代理方会强持有委托方,而委托方需要有一个关于代理方的声明,以weak形式声明可以规避循环引用。

KVO

1. 什么是KVO?

2. KVO的实现机制和原理

当我们注册一个对象的观察者时,系统会在运行时动态创建一个观察对象的子类,并将原本指向观察对象的isa指针,指向新创建的子类上(修改isa指针的指向,就是isa混写技术的标志),子类重写对应的setter方法,重写后的setter方法负责通知所有观察对象。

// KVO在子类重写的setter方法
- (void)setValue:(id)obj {
    [self willChangeValueForKey:@"keyPath"];
    [super setValue:obj];
    [self didChangeValueForKey:@"keyPath"];
}

KVO是通过重写setter方法来实现的,那么如果不通过setter方法,比如直接使用KVC来修改value、或者直接修改成员变量,KVO还能否生效?为什么?

能否触发KVO的监听取决于是否调用了setter方法,使用KVC修改value会触发setter方法,所以能被监听到。但也可以在修改成员变量时,模拟KVO对setter方法的重写,修改前调用[self willChangeValueForKey:@"keyPath"],修改后调用[self didChangeValueForKey:@"keyPath"],实现手动触发KVO的回调。

KVC

1. 什么是KVC?

KVC是Key-value coding的缩写,是iOS系统为我们提供的一种键值编码技术。

2. KVC是否违背了面向对象编程思想?

KVC违背了面向对象编程思想。如果我们知道了某个类内部的私有成员变量名称,那么我们在外部可以通过已知的Key来设置或访问其私有变量。

3. valueForKey:的实现流程

  1. 系统首先通过Key判断该实例变量是否实现了get方法,如果get方法存在,则直接调用get方法,并结束整个流程;
  2. 如果get方法不存在则判断实例变量是否存在,若实例变量存在,则获取该实例变量的值,并结束整个流程;
  3. 如果实例变量不存在,系统会调用valueForUndefinedKey:方法,抛出异常NSUndefinedKeyException,并结束整个流程。

注:在判断实例变量是否存在时,系统给我们提供了一个可屏蔽的开关(+(BOOL)accessInstanceVariablesDirectly),默认返回YES,当我们重写该方法并返回NO时,即使类中存在该成员变量我们也获取不到。

get方法的判断规则

实例变量的判断规则

4. setValue:forKey:的实现流程

  1. 系统首先通过Key判断该实例变量是否实现了set方法,如果set方法存在,则直接调用set方法,并结束整个流程;
  2. 如果set方法不存在则判断实例变量是否存在,若实例变量存在,则对该实例变量赋值,并结束整个流程;
  3. 如果实例变量不存在,系统会调用setValue:forUndefinedKey:方法,抛出异常NSUndefinedKeyException,并结束整个流程。

注:实例变量的判断同valueForKey:方法,可通过开关控制。

上一篇下一篇

猜你喜欢

热点阅读