美文网首页
深入理解OC面向对象

深入理解OC面向对象

作者: juriau | 来源:发表于2022-01-12 10:56 被阅读0次

目录

  • 1.面向对象

    • 1.三要素
    • 2.属性
  • 2.深拷贝与浅拷贝

    • 1.Foundation框架中的对象
    • 2.自定义对象
  • 3.对象等同性

    • 1.NSString对象判断相等
    • 2.自定义对象判断相等
  • 4.KVC / KVO

    • 1.KVC的过程
    • 2.KVO的原理
  • 5.Category

    • 1.Category的使用场合
    • 2.Category的实现原理
    • 3.关联对象
  • 6.+load和+initialize

一、面向对象

1.面向对象三个要素

1.1 封装

概念:隐藏对象的数据,不允许外界直接访问,而是需要通过相应的方法来访问和修改数据。
实现:OC使用属性(property)来封装对象中的数据。

1.2 继承

概念:通过继承子类可以得到父类属性和方法,在父类的基础上建立新的类。
实现:OC的消息机制在自己的类信息中找不到对应方法时,会通过superclass指针去父类的类信息中查找。

1.3 多态

概念:子类重写父类方法,父类指针指向子类,父类指针调用方法时会调用子类重写的方法。
实现:

Q:iOS如何实现多继承?

最符合的方式是消息转发

其他的方式也有

  • 组合:将类A和类B的实例对象作为类C的属性;
  • delegate和protocol:将C类需要继承的方法以及属性在ClassA和ClassB中各自声明一份协议,C类遵守这两份协议,同时在C类中实现协议中的方法以及属性

Q:OC有重载吗?

重载说的是函数名相同,但是参数不同,OC没有。swift支持重载。

2.属性(@property)

在类定义中声明的属性,编译器会自动生成一个与该属性同名且下划线开头的成员变量,同时自动生成该实例变量的存取方法。

可以通过修改属性的修饰词来控制存取方法的生产,修饰词有四种:

  • 原子性:atomic、noatomic
  • 内存管理语义:copy、strong、assign、weak
  • 读写权限:readonly、readwrite
  • 方法名:getter=、setter=

二、深拷贝与浅拷贝

深拷贝就是内容拷贝,浅拷贝就是指针拷贝。本质区别在于:

  • 是否开启新的内存地址
  • 是否影响内存地址的引用计数

1.Foundation框架中的对象

对Foundation框架中的非容器对象(NSString、NSNumber)和容器对象(NSArray、NSDictionary)使用copymutableCopy的情况如下:

需要注意的是,容器对象的深拷贝其实是单层深拷贝
单层深拷贝:虽然为数组对象开辟了新空间,不过存放在数组的值还是原数组元素值。

实现容器对象的完全深拷贝可以使用专门的方法
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;

Q:为什么NSString属性用copy修饰?
因为可能会把NSMutableString对象赋值给NSString属性;
如果使用strong的话,对象外面的可变对象发生改变时,对象内部的NSString属性也会跟着变化。
而使用copy可以避免这个情况,赋值时会拷贝一份不可变副本赋值给NSString属性。

2.自定义对象

遵循 NSCopying 协议,实现- (id)copyWithZone:(NSZone *)zone方法。

三、对象等同性

1.NSString对象判断相等

NSString中判断相等有三个方法:isEqualisEqualToString==,它们的区别在于:

  • ==:直接比较两个对象的地址
  • isEqual:NSString重写了该方法,首先判断两个对象的类,然后判断两个对象的内容。
  • isEqualToString:判断两个字符串内容是否相同。
    因为少了检测参数类型,所以比isEqual快。
    事实上isEqual在检测完参数类型后,就调用了该函数。

2.自定义对象判断相等

重写isEqual方法:

  • 首先,直接判断两个指针是否相等;
  • 接下来,判断是否都属于一个类。
  • 最后,检测每个属性值是否相等。

另外:重写了isEqual方法,那么也必须重写hash方法。因为如果两个对象相等,那么它们也必须有相同的哈希值。不过反之则不成立。

@interface HJPerson : NSObject
@property (nonatomic, copy) NSString* firstName;
@property (nonatomic, copy) NSString* lastName;
@property (nonatomic, assign) NSUInteger age;
@end

@implementation HJPerson
- (BOOL)isEqual:(id)other{
    if (self == other) return YES;
    if ([self class] != [other class]) return NO;
    
    HJPerson* otherPerson = (HJPerson*)other;
    if (![self.firstName isEqualToString:otherPerson.firstName]) return NO;
    if (![self.lastName isEqualToString:otherPerson.lastName]) return NO;
    if (self.age != otherPerson.age) return NO;
    
    return YES;
}
- (NSUInteger)hash{
    NSUInteger firstNameHash = [self.firstName hash];
    NSUInteger lastNameHash = [self.lastName hash];
    NSUInteger ageHash = self.age;
    return firstNameHash ^ lastNameHash ^ ageHash;
}
@end

四 、KVC / KVO

1.KVC的过程

(1)按照命名规范,先查找相关的方法,如果没有找到;
(2)按照命名规范,找相关的成员变量,如果没有找到;
(3)调用setValue:forUndefinedKey;
(4)如果都没有找到相关的方法实现就抛出异常。


2.KVO实现机制

一个类添加观察者后,runtime创建了一个该类的派生类!实例对象的isa指向这个派生类。如果该类有setter方法,在派生类中会重写了setter方法。

重写的setter函数的实现大概是这样:

然后在didChangeValueForKey中调用观察者的observeValueForKeyPath。

Q:如何手动触发KVO?

(1)关掉属性的自动触发
(2)在setter方法中,手动调用willChangeValueForKey和didChangeValueForKey

五、Category

1.Category的使用场合

  • 将类拆解为几个模块
  • 为现有的类添加一些方法

2.Category的实现原理

Category的底层结构其实是struct _category_t 结构体,里面存储着Category的方法、属性、协议等信息。在运行时、runtime初始化的时候,会将category的数据,合并到类信息中。

Q:Category和Extension的区别是什么?

  • Extension的数据在编译时就合并到类信息中了。
  • Category的数据在运行时才会合并到类信息中。

Q:类和分类中的方法名相同,会调用哪个方法?

  • 对于类中和分类中的同名方法,会优先调用分类的方法,因为分类的方法会放在原来的方法前面。

  • 对于多个分类中的同名方法,则需要看编译顺序。最后面编译的分类,其方法会放在前面。

注:核心源代码attachCategories()、attachLists()。

3.关联对象

Category不能添加成员变量,关联对象用于给Category“添加成员变量”。

关联对象的API:

  • 添加关联对象:void objc_setAssociatedObject(id object, const void * key,
    id value, objc_AssociationPolicy policy)

  • 获得关联对象:id objc_getAssociatedObject(id object, const void * key)

  • 移除所有的关联对象:void objc_removeAssociatedObjects(id object)

关联对象的原理:

关联对象是使用哈希表实现的,将被关联的对象作为key,映射到一个子哈希表上。然后再通过变量名找到值。而不是将变量放在被关联的对象中。

Q:Category能否添加成员变量?为什么?

不能。因为Category的底层数据结构,它的结构体中没有成员变量只有属性。

六、+load和+initialize

1.+load方法

+load方法会在这个类加载到内存中被调用。或者说在runtime加载类、分类的时候调用。

注意:

  • 就算在mian.h中没有导入这个类或者没有使用这个类,+load方法也会调用。
  • +load方法在被runtime自动调用时,是直接取出+load方法,而不是经过objc_msgSend,所以不遵循继承规则,类和分类的load方法都会被调用
MJPerson +load
MJStudent +load
MJPerson (Test1) +load
MJPerson (Test2) +load
MJStudent (Test1) +load
MJStudent (Test2) +load

2.+initialize方法

+initialize方法是在类第一次发送消息的时候调用。

相关文章

  • 我所理解的iOS runtime

    从一下方面来深入研究: 理解面向对象的类到面向过程的结构体 深入理解OC消息转发机制 理解OC的属性propert...

  • 深入理解OC面向对象

    目录 1.面向对象1.三要素2.属性 2.深拷贝与浅拷贝1.Foundation框架中的对象2.自定义对象 3.对...

  • OC总结(1)

    1.如何理解OC C语言是一种面向过程的语言,OC则是面相对象的语言,所以想要理解OC就要先了解面向过程和面向对象...

  • 正确使用面向对象之我见

    说说对面向对象的理解吧.最简单粗暴的回答当然是"封装,继承,多态"随着使用面向对象语言的一步步深入,比如JS与OC...

  • 2018-01-17 OC基础概念

    OC的理解与特性 OC 作为一门面向对象的语言, 自然具有面向对象的语言特性: 封装 继承 多态. 它既具有静态语...

  • 读码笔记-Aspects-iOS源码图解笔记

    “读这个干嘛” 1.加深面向对象和面向切面编程结合的实践理解2.加深OC语言理解 “有啥特色?” 在OC的源码里,...

  • iOS常见面试题归纳(一)基础篇

    1、OC的理解与特性: OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言...

  • 最全梳理,iOS面试必看!!!

    序言 OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言...

  • 最全最新梳理,iOS面试必看!!!

    序言 OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言...

  • oc-理解对类、对象等概念

    OC是基于C语言的面向对象的语言。C语言中没有对象的概念,为了便于开发者理解和使用面向对象的思想,OC将C语言中的...

网友评论

      本文标题:深入理解OC面向对象

      本文链接:https://www.haomeiwen.com/subject/xjkyrktx.html