news 2026/7/22 15:33:33

iOS课程观看笔记(二)---OC语言相关

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
iOS课程观看笔记(二)---OC语言相关

开局一张图

围绕着OC语言相关问题,大致涉及到图片中所有的内容。

分类(Category)

你用分类都做了哪些事情?
  1. 声明私有方法
  2. 分解体积庞大的类文件
  3. 把Framework的私有方法公开

声明私有方法这个,我感觉就是将原来的写在原类中的私有方法,在分类中进行声明。
比如定义一个分类,只有头文件放到对应宿主.m里,满足私有方法的声明和使用,不暴露具体实现。

分类的特点:
  1. 运行时决议
    指的是在运行时,通过runtime将分类里面的内容添加到宿主类里面
  2. 可以为系统类添加分类
分类中都可以添加哪些内容?
  1. 实例方法
  2. 类方法
  3. 协议
  4. 属性(只声明了get和set方法,并没有实现get和set方法,也没有生成实例变量)

分类的结构:


具体代码不再具体分析,可参考iOS分类Category的本质

本文只摘抄部分上文中没有的内容,或者比较重要的内容。

这里只分析分类中的实例方法。

在编译阶段:

编译器将category里面的内容,编译成category_t类型的结构。

在运行阶段:
  1. runtime将每一个分类中的实例方法组成一个数组,然后,将这些数组再组合到一个大数组中,
  2. 然后从最后一个元素(数组类型)开始,添加到分类的instance_methods数组中,
  3. 再将拼接好的二维数组instance_methods放入宿主类的class_rw_t的methods当中。
举个例子:

假如某个类YZPerson有三个分类:YZPerson+eat.m、YZPerson+run.m、YZPerson+walk.m

首先,将每个分类里面的实例方法组合成一个数组,然后,再将三个分类组合成一个大数组。
这样,分类中的实例方法列表,就是一个二维数组。

假如,上面三个分类,第一个分类里面有2个实例方法,第二个分类里面有1个实例方法,第三个分类里面有3个实例方法,那么,该实例方法在分类存储形式如下图中的二维数组类似。
以上是将分类合并成一个大数组,其顺序是按照编译顺序(最先编译的在数组最前面)

然后,再通过一个while循环,从数组的最后一个元素(也是数组)开始,一个一个添加到分类的instance_methods里面。


然后,将分类的instance_methods这个二维数组,拼接到rw的methods上,也就是拼接到原类的methods方法列表中。
并且从attachLists方法里面可以看出,是将分类实例方法列表插入到宿主类的方法列表的最前面。


这样,最后编译的分类里面,方法最先被调用。

属性、协议的添加方法与上面实例方法添加方法类似。

  1. 分类添加的方法可以“覆盖”原类方法(当然不是真的覆盖)
  2. 两个分类,里面有一个同名方法,最后编译的分类里面的方法被调用。
  3. 名字相同的分类会引起编译报错

关联对象

问:能否为分类添加成员变量?

不能

问:能否为分类添加属性?

idobjc_getAssociatedObject(id _Nonnull object,constvoid*_Nonnull key)voidobjc_setAssociatedObject(id _Nonnull object,constvoid*_Nonnull key,id _Nullable value,objc_AssociationPolicy policy)voidobjc_removeAssociatedObjects(id _Nonnull object)
问:为分类添加的属性被添加到了哪里?

没有被添加到原宿主类中,而是被添加到。。。


属性、实例变量、成员变量的区别?

属性,property,是指的右@property建立的
例如:@property (copy, nonatomic) NSString *postId;
@property负责三个事情:

  1. set,get方法的声明
  2. set,get方法的实现
  3. 生成_postId的实例变量

成员变量指的是

@interface{intage;NSObject*obj1;}@end

大括号中间的内容

实例变量ivar(instance variables),指的是{}中声明的变量都是实例变量

成员变量通常就是实例变量,二者基本可以视为同义词。

成员变量 = 实例变量

属性property
实例变量instance variable / ivar
成员变量member variable / data member通常也称 instance variable


扩展(Extension)

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

代理(Delegate)

代理分三个模块:协议、委托、代理
协议,就是@property
委托,就是协议调用协议方法的地方,指定代理
代理,就是实现协议里面具体方法的地方

是一种软件设计模式
传递方式一对一
代理也可以添加属性

MJ说:delegate不是代理设计模式,NSProxy是代理设计模式
于海说:delegate是代理设计模式

那么,delegate是不是代理设计模式呢?

delegate 在中文 iOS 开发习惯中经常被叫作“代理”,但严格按设计模式分类,它主要是委托模式,不是 GoF 的代理模式。NSProxy 更接近 GoF 代理模式的实现工具。所以 MJ 的说法在严格的设计模式语境下更准确;于海的说法符合国内 iOS 开发中的宽泛叫法。

问:如何实现代理的一对多?

即,同一个代理,被多个对象监听

方法一:

将代理设置成数组、集合,而不是单单的一个weak属性值
类似:

@property(nonatomic,strong)NSMutableArray<id<TestSubViewDelegate>>*__nullable delegates;

需要注意的是,在消耗的时候,要手动销毁delegates

-(void)destory{[self.delegates removeAllObjects];self.delegates=nil;}

iOS 实现一对多代理方案

不过,最好使用NSMapTable NSHashTable NSPointerArray这些数据类型
因为,这几个数据类型,里面存放的元素都是weak指针引用的,销毁的时候不需要手动销毁

iOS开发-NSMapTable NSHashTable NSPointerArray的使用

方法二:

利用消息转发机制
iOS:利用消息转发机制实现多播委托


通知(NSNotification)

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

问:如何实现通知机制?

在通知中心,有一个Notification_Map字典,里面存储着以通知名称为key,观察者组成的数组作为value


KVO

KVO是Key-value observing的缩写
KVO是Objective-C对观察者设计模式的一种实现
Apple使用了isa混写(isa-swizzling)来实现KVO


isa混写技术:
指的就是将isa指针动态重新指向新的类

setter方法重写的方法:

问:通过kvc设置value,kvo能否生效?

可以
KVC改变属性值,会进入属性值的setter方法,从而触发KVO

问:通过成员变量直接赋值value,kvo能否生效?

不可以
但,可以通过手动修改setter方法,触发KVO

[self willChangeValueForKey:@"name"];[super setName:name];[self didChangeValueForKey:@"name"];

使用setter方法改变值,KVO会生效
使用setValue:forKey:改变值,KVO会生效
成员变量直接修改需手动添加某些代码,KVO才会生效


KVC

KVC是Key-value coding的缩写。
里面有两个重要的方法:

-(id)valueForKey:(NSString*)key;-(void)setValue:(nullable id)value forKey:(NSString*)key;
问:KVC是否有违面向对象思想

KVC只要知道某个对象的私有变量名称key,可以在外部将其value进行修改,也就是有违面向对象思想的。

valueForKey:的系统实现流程:


valueForKey:说白了就是通过一个key找到对应的value
找value可以是通过getter方法找,也可以通过直接找对应的实例变量
也就是,一个是方法,一个是实例变量,两种方法
图中
Accessor Method is exist?
就是通过getter方法找,有的话直接调用

Instance Var is exist?
就是有没有对应的实例变量,有的话调用

问:Accessor Method如何找方法呢?

通过getKey、key(正好是getter方法)、isKey三个方法,如果有则YES

这三个都是方法

问:+(BOOL)accessInstanceVariablesDirectly的作用?

系统给我们提供了一个方法:
+(BOOL)accessInstanceVariablesDirectly,默认是返回YES

在返回YES的基础上,才会调用Instance Var is exist,判断是否存在相应的实例变量或者相似的实例变量

如果我们重写该方法,使其返回NO,那么直接报没有找到对应的值处理;不再进行实例变量的判断。

问:Instance Var is exist?判断规则是什么?

通过查找是否存在:_key、_isKey、key、isKey四个实例变量,如果有则YES

这四个都是实例变量

问:如果valueForKey:没有找到对应的value,会怎样?

如果valueForKey:没有找到对应的value,会调用valueForUndefinedKey:
从而造成崩溃

YZPerson*person1=[[YZPerson alloc]init];NSLog(@"person1.age = %@",[person1 valueForKey:@"age"]);

setValue:forKey:的系统实现流程:

里面的具体方法与流程与valueForKey:类似,不再进行具体分析。


属性关键字

问:属性关键字可以分为哪几类?

读写权限:readonly、readwrite(默认)
原子性:atomic(默认)、nonatomic
引用计数
setter\getter

atomic可以保证获取和赋值是线程安全的
但是,并不能保证在使用过程中是线程安全的

引用计数:
retain\strong
assign\unsafe_unretain
weak
copy

问:assign和weak的区别有哪些?

assign
可以修饰基本数据类型,如int、BOOL等
可以修饰对象类型,但不改变其引用计数器
当使用assign修饰对象,在对象释放的时候,会产生悬垂指针

weak
不可以修饰基本数据类型
修饰对象类型,但不改变其引用计数器
当使用weak修饰对象,在对象释放的时候,会自动置为nil

问:关于空指针、野指针、悬垂指针的区别

空指针:指针指向的地址为空的指针
野指针:指针创建时未初始化。指针变量刚被创建时不会自动成为NULL指针,它会随机指向一个内存地址。
垂悬指针:指针所指向的对象已经被释放或者回收了,但是指向该对象的指针没有作任何的修改,仍旧指向已经回收的内存地址。

更多学习关于悬垂指针
按照上面的说法,我们之前很多说的野指针错误,严格说来并不是野指针错误,而是悬垂指针

问:浅拷贝、深拷贝


浅拷贝并没有新建一块内存
浅拷贝对原来的对象引用计数+1

深拷贝会新建一块内存,与原来的内存里面内容一样
深拷贝对原来的对象引用计数不变


如果赋值过来是NSMutableArray,copy后其实是NSArray,如果对其进行添加或者删除操作,会造成程序崩溃

问:为何会做 _obj != obj 的判断?不做可以吗?

如果不做,则先进行[_obj release];也就是原来的对象可能已经被释放掉了。再进行[obj retain]操作,会造成程序异常。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 15:29:38

投票工具选型总结:按场景(校园/政务/企业/设计)推荐最佳平台

一、四大场景常见投票活动一览不同场景对投票工具的诉求差异极大——校园活动看重“免费易用”&#xff0c;政务评选要求“防刷合规”&#xff0c;企业评优需要“公平数据”&#xff0c;设计类赛事讲究“视觉多媒体”。本文按场景拆解选型逻辑&#xff0c;帮你匹配最合适的平台…

作者头像 李华
网站建设 2026/7/22 15:24:13

【Python课程设计/毕业设计】基于Python的膳食营养知识库管理系统 智能饮食分析与个性化食谱生成系统【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/22 15:23:26

022、VanillaNet与FasterNet骨干:极简架构与快速网络的检测性能对比

022、VanillaNet与FasterNet骨干&#xff1a;极简架构与快速网络的检测性能对比 上个月调YOLOv8的时候遇到个怪事——换了个轻量骨干&#xff0c;推理速度没提上去&#xff0c;mAP反而掉了两个点。排查了一整天&#xff0c;最后发现是特征图下采样次数没对齐&#xff0c;导致Ne…

作者头像 李华
网站建设 2026/7/22 15:18:37

C++ STL map与multimap:红黑树实现、核心操作与实战场景详解

1. 项目概述&#xff1a;从“字典”到“关联数组”的思维跃迁在C的世界里&#xff0c;处理数据对&#xff08;Key-Value Pair&#xff09;的需求无处不在。想象一下&#xff0c;你要写一个学生成绩管理系统&#xff0c;需要根据学号快速查到对应的姓名和分数&#xff1b;或者你…

作者头像 李华