OC语言特性

OC语言特性

前言

我们今天从iOS的分类关联对象技术、扩展代理通知KVOKVC实现机制和属性关键字来学习下Objective-C语言的特性。

分类(Category)

  • 我们用分类做了哪些事情呢
    • 声明私有方法
    • 分解体积庞大的类文件
    • 把Framework的私有方法公开化
  • 分类的特点
    • 运行时决议:编译时,并未把分类的方法添加到宿主类中,而是在运行时,通过runtime技术添加到宿主类中
    • 可以为系统类添加分类
  • 那么分类中都可以添加哪些内容?
    • 实例方法
    • 类方法
    • 协议
    • 属性(只是声明了get、set方法,并没有生成实例变量)
  • 从分类的源码的分析可以得出的结论:
    • 分类添加的方法可以”覆盖”原来类的方法
    • 多个分类的同名方法,最后参与编译的分类的方法会生效
    • 名字相同的分类会引起编译报错

关联对象

  • 场景:怎样为分类添加“成员变量”
    • 可以添加成员变量
    • 不能在分类的声明和实现的时候直接添加成员变量
    • 可通过关联对象技术为分类添加
  • 关联对象技术的相关函数:
    • id objc_getAssociatedObject(id object, const void* key)
    • void objc_setAssociatedObject(id object, const void* key, id value, objc_AssociationPolicy policy)
    • objc_AssociationPolicy:关联策略,value是以什么方式(copy、retain、assign)关联到宿主对象上面
    • void objc_removeAssociatedObjects(id object):移除所有的关联对象
  • Q:使用关联对象技术添加的成员变量,添加到哪里了呢?
  • 关联对象的本质:
    • 关联对象是由系统提供的AssociationsManager管理,并在AssociationsHashMap存储的。
    • 所有对象的关联内容都在同一个全局容器中。并且为不同分类添加的值都存放在同一个全局容器当中。
  • 关联对象技术的数据结构

  • Q:怎样清除一个关联对象被关联的值呢?
    • 调用setAssociatedObject方法,value传值nil即可;其方法内部会把关联的值给擦除掉

扩展(Extension)

  • 一般用扩展来做什么
    • 声明私有属性
    • 声明私有方法
    • 声明私有成员变量
  • 扩展的特点
    • 编译时决议
    • 只以声明的形式存在,多数情况下寄生于宿主类的.m中。
    • 不能为系统类添加扩展

代理

  • 什么是代理:
    • 含义:准确的说是一种软件设计模式
    • iOS当中以@protocol形式提现
    • 传递方式是一对一
  • 代理的工作流程是怎样的
    • 涉及的概念:委托方、协议(方法和属性)、代理方

  • 一般声明为weak以规避循环引用。

通知(NSNotification)

  • 什么是通知:
    • 含义:是使用观察者模式来实现的用于跨层传递消息的机制
    • 传递方式为一对多

  • 如何实现通知机制?

  • 在通知中心会维护一个Map表;

KVO

  • 什么事KVO技术:
    • 概念:KVO是key-value observing的缩写。
    • KVO是OC对观察者模式的一种实现
    • Apple使用了isa混写(isa-swizzling)来实现KVO

  • 重写的setter中添加的方法:
    • -(void)willChangeValueForKey:(NSString *)key;
    • -(void)didChangeValueForKey:(NSString *)key;

  • Q:通过kvc设置value能否生效?
  • 答案:可以
  • 为什么能生效:涉及到KVC的实现原理

  • Q:通过成员变量直接赋值value能否生效?
  • 答案:不能;可以手动触发KVO实现;自行实现willChangeValueForKey和didChangeValueForKey方法。

  • 结论:
    • 使用setter方法改变值KVO才会生效。
    • 使用setValue:forKey:改变值KVO才会生效。
    • 成员变量直接修改需手动添加KVO才会生效。

KVC

  • KVC的概念:KVC是key-value coding的缩写;是苹果为我们提供的一种编码技术
  • 主要有两个方法:
    • -(id)valueForKey:(NSString *)key; 通过key获取值
    • -(void)setValue:forKey:(NSString *)key; 通过key去设置值
  • 使用KVC编码技术,是否会破坏面向对象的编程思想?
    • 若已知类的私有变量的名称,在外界就可通过key为实例设置或者获取值。
    • 从这一点来说,是会破坏面向对象的编程思想。
  • valueForKey的实现流程:

  • Accessor Method 存在的判断规则:只要实现其中一种即可:
  • Instance var 的说明:同名、相似同名变量;以下都可以获取到变量值
    • _key
    • _isKey
    • key
    • isKey
  • setValue:forKey: 的实现流程:

  • 判断setter方法是否存在
  • 判断实例变量是否存在
  • 抛出未定义key的异常

属性关键字

  • 属性关键字可以分为哪几类:
    • 1.读写权限 readonly、readwrite(默认)
    • 2.原子性 atomic、nonatomic
      • atomic:赋值和获取保证安全;但是对属性对象进行添加和移除对象是无法保证线程安全的
    • 3.引用计数
      • retain/strong
      • unsafe_unretained/assign
      • weak
      • copy
  • 场景:assign和weak的区别
  • assign的特点:
    • 1.修饰基本数据类型,如int,BOOL等
    • 2.修饰对象类型时,不改变其引用计数
    • 3.会产生垂直指针(野指针);(对象释放后,assign指针仍执行原对象的内存地址,这时候如果通过assign指针继续访问原对象,可能会存在内存泄露导致崩溃)
  • weak的特点
    • 1.不改变被修饰对象的引用计数(多数用于避免循环引用)
    • 2.所指对象被释放之后会自动置为nil
  • copy
  • 深浅拷贝
  • 浅拷贝:
    • 1.会增加被拷贝对象的引用计数;
    • 2.就是对内存地址的赋值,让目标对象指针和源对象指向同一片内存空间
  • 深拷贝:
    • 1.不会增加被拷贝对象的引用计数;
    • 2.让目标对象指针和源对象指向两片内容相同的内存空间
  • 区分:
    • 1.是否开辟了新的内存空间
    • 2.是否影响了被拷贝对象引用计数
  • copy 关键字

  • @property (copy) NSMutableArray *array; 存在哪些问题?
    • 如果赋值过来的是NSMutableArray,copy之后是NSArray,不可变
    • 如果赋值过来的是NSArray,copy之后也是NSArray,且是浅拷贝

总结:

  • 请简述分类的实现原理(运行时+函数调用顺序+同名方法生效)

  • KVO的实现原理是怎样的(观察者模式+isa混写技术)

  • 能否为分类添加成员变量(关联对象技术)

  • 代理和通知的区别(实现模式和传递方式)

  • 分类和扩展的区别(运行、编译决议+声明方法的实现+系统类)

  • assign和weak的区别(修饰对象类型+引用计数+特点)

  • 深浅拷贝的区别(新的内存空间+被拷贝对象引用计数)

最后

如果对大家有帮助,请github上follow和star,本文发布在戴超的技术博客,转载请注明出处

Loading Disqus comments...
Table of Contents