高频问题:
OOM:
监控可以用didReceiveMemoryWarning
也可以类似flex ,通过malloc_get_all_zones可以获取所有堆区的对象,通过objc_getClass获取对应的对象名,通过class_getInstanceSize获取单个对象的大小。进行引用分析,获取当前内存占用
Facebook的方案是排除法,判断终止进程原因,排除已知原因
腾讯的做法是OOMDetector
可以通过malloc_logger实现对于malloc/free的监控,记录内存
AutoreleasePool与ARC的关系?
AutoreleasePool可以理解为一个对象,在ARC环境下,这个对象本身也是自动计数的,当这个pool的引用计数为0时,就被清掉了,这是手动声明时候的情况,当系统自动为我们建立AutoreleasePool以及在runloop结束时释放就是系统的事情了。但同时AutoreleasePool不同于一般的对象指针,它可以持有多个对象,当pool被release的时候,其会向其持有的所有对象发送release消息,在非ARC环境下用来延长对象的作用域是很有效的。我们知道ARC只是编译器在帮我们自动添加retain和release,而并非垃圾回收器,这样以来,就会不可避免的产生一些内存问题,
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
.a 和 .framework 的区别是什么?
.a 是单纯的二进制文件,.framework是二进制问价+资源文件。
其中.a 不能直接使用,需要 .h文件配合,而.framework则可以直接使用。
.framework = .a + .h + sorrceFile(资源文件)
RunLoop
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)
一个HTTP流程:
url - DNS查ip ,dns自己有cache,未命中再去找dns服务器 -UDP - ip -Mac地址
埋点系统设计
GCD.串行并行队列
二叉搜索树的判断
string strong copy的区别
当原字符串是NSString时,由于是不可变字符串,所以,不管使用strong还是copy修饰,都是指向原来的对象,copy操作只是做了一次浅拷贝。
而当源字符串是NSMutableString时,strong只是将源字符串的引用计数加1,而copy则是对原字符串做了次深拷贝,从而生成了一个新的对象,并且copy的对象指向这个新对象。另外需要注意的是,这个copy属性对象的类型始终是NSString,而不是NSMutableString,如果想让拷贝过来的对象是可变的,就要使用mutableCopy。 所以,如果源字符串是NSMutableString的时候,使用strong只会增加引用计数。 但是copy会执行一次深拷贝,会造成不必要的内存浪费。而如果原字符串是NSString时,strong和copy效果一样,就不会有这个问题。
一般怎么检查野指针,zombie对象怎么知道是野指针
https://www.jianshu.com/p/7bb92761f2f5
消息转发
从全局来看,消息转发机制共分为3大步骤:
1.Method resolution 方法解析处理阶段
2.Fast forwarding 快速转发阶段
3.Normal forwarding 常规转发阶段
动态卡片vm,类似字节lua
概念上类似于阿里开源的LuaView
分类为什么不能添加属性
分类添加方法的原理和顺序
- 最后添加分类的方法 new_method ,从整个方法的内存从首端开始覆盖
- 编译顺序越靠后的分类方法的优先级越高
所以在调用实例对象的方法时,会优先调用分类中的实例对象方法,具体的分类顺序需要在 XCode 中设置分类文件的编译顺序,在 Project-BuildPhases-Compile Sources 中进行设置
https://juejin.cn/post/6953474692363583525
https://fatofyoung.github.io/2018/06/13/OC%E5%88%86%E7%B1%BB%E5%8E%9F%E7%90%86/
uicontrol手势冲突
https://juejin.cn/post/6908553699732226061
怎么解决单双击冲突
requireGestureRecognizerToFail 设置手势的优先级,同样,分页控制器在左滑和系统左滑冲突时也可以这么解决
iOS 事件(UITouch、UIControl、UIGestureRecognizer)传递机制 - (jianshu.com) 聊聊NSInvocation和NSMethodSignature_Deft_MKJing的博客-CSDN博客
UITableView继承链?UITableView -> UIScrollView -> UIView -> UIResponder -> NSObject
UIresponder和UIcontrol的区别是啥?UIControl继承自UIView,UIReponder是iOS用于处理触摸事件
的基类,UIControl对其进行了深度包装,以target-action的模式进行调用。触摸事件传递流程是啥样的?分为事件传递链和响应链,传递链通过hittest函数和pointside递归的
判断子view是否可以响应事件,直到递归遍历到最后一个view,响应链则是消费事件的过程,从子 view向其的vc,superView传递触摸事件。优先级的话手势识别高于view的触摸事件,系统的 uicontrol高于手势,自定义的低于手势。如何扩大UIbutton点击范围?两种方法,重写pointinside和hittest
如何扩大手势点击范围?或者扩大一个小图片的点击范围?图片话调节内边距即可
获取当前viwe的vc方法?方法一:通过响应链机制,寻找view的下一级响应者,因为view的下一级
响应链是其vc 方法二:通过KeyWindows获取对应的rootVC一直朝下遍历,获取presetedVC知
道最后一个VC消息转发阶段流程是什么样的?具体有哪些方法?resolveMethod -> forwardingTarget -> methodSinature->forwardInvocation 第三步会获取对应的方法签名,如果能获取到可以在第四步 直接将这个方法以NSInvocation形式转发给其他对象处理
NSInvocation和NSMethodSignature的区别是啥?NSMethodSignature是方法编码过后的签名,例如 NSString的类方法isEqualToString: 的方法签名为B24@0:8@16,如下所示 @encode(BOOL) (B) 返回值 @encode(id) (@) 默认第一个参数 self
@encode(SEL) (:)默认第二个参数 _cmd
@encode(NSString ) (@) 实际上的第一个参数NSString* iOS中的method即由SEL、IMP和签名组成,SEL是method检索的方式,可以通过SEL在method list中找到对应的方法,IMP则是函数指针指向方法的本身,签名包括了函数头中的各种信息。 NSInvocation则是消息在OC中对象的形式存在,是一种更高级的转发机制可以通过添加target、 签名、参数这些强行执行方法消息转发可以做什么?怎么做的?热更新、多重代理和多继承
Runtim相关函数有哪些?贼多,建议查 Objective-C Runtime | Apple Developer Documentation
线程锁有哪些?iOS多线程安全-13种线程锁%"#$ (juejin.cn)
semaphore和nslock有啥区别?优缺点是啥?
怎么通过gcd实现读写锁?Dispatch_barrity_async
循环引用是啥?有哪些会造成?iOS解除Block循环引用,你只知道_weak就out啦知更鸟
CoolLee的博客-CSDN博客
block中的强引用是对self指针的强引用所以简单使用weak/strong就可以解决循环引用问题,但
是NSTimer中的循环引用是对整个对象的强引用NStimer循环引用是怎么造成?怎么解决?NSTimer会强引用整个对象,对象持有Timer就会引起强
引用。方法1:及时结束Timer运行,使用invalidata结束运行并置整个Timer为nil 方法2:target不指向自身,指向一个其他对象 方法3:使用NSProxy替代self,消息转发阶段转发消息回原类NSProxy是啥?有啥用?NSProxy是一个等同于NSObject的基类,实现了
的协议,自身没 有任何实现,主要用于转发消息的基类,可以继承自这个基类,实现消息转发中的方法可以将消 息转发给其他对象。可以用于实现oc中本不支持的多继承,解决NSTimer中的循环引用。
NSProxy和NSObject的区别?
-
虽然都需要实现了
协议,主要差别在消息转发流程中, NSObject会走完完整的消息转发机制,NSProxy直接回调-methodSignatureForSelector:/- forwardInvocation:,消息转发过程比class NSObject要简单得多,NSProxy会将自省相关的selector
直接forward到-forwardInvocation:回调中,例如 - (BOOL)isKindOfClass:(Class)aClass;- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector;
_cmd是啥?表示这个方法本身
block如何获取外部变量?
+load方法和initialize方法加载顺序?
IOSkeychain
Socket 场链接 内购 gcd
如何捕获**crash **
https://www.jianshu.com/p/5fcf7bb7955f
动态库和静态库
block 为什么用copy修饰 Block实现原理
https://juejin.cn/post/6844904040954871815
setObject:forKey:和setValue:forKey:的
kvc 和kvo
kvc set:简单来说就是如果没有找到Set
当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方***负责在调用原 setter方法之前和之后,通知所有观察对象值的更改。最后把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。
原来,这个中间类,继承自原本的那个类。不仅如此,Apple 还重写了 -class 方法,企图欺骗我们这个类没有变,就是原本那个类。更具体的信息,去跑一下 Mike Ash 的那篇文章里的代码就能明白,这里就不再重复。
https://juejin.cn/post/6844903602545229831
介绍下oc
RunTime:
首先 OC 是 C 语言的超集,因为 runtime 这个库使得C语言有了面向对象的能力:
OC 对象可以用C语言中的结构体表示,而方法可以用C函数来实现,这些结构体和函数被 runtime 函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
OC 是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。
这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。这个运行时系统即Objc Runtime。Objc Runtime基本上是用C和汇编写的。
https://www.jianshu.com/p/d7818dcb21de
静态库和动态库:
https://juejin.cn/post/7040003550977458207
编译和链接:
http://www.360doc.com/content/17/0111/22/32626470_621879084.shtml
集合类型 copy 操作和 mutableCopy 操作
一个类遵循 NSCopying, NSMutableCopying 协议并且实现相对应的初始化方法后,这个类就具有对象拷贝的能力。如果你自定义类没有遵守协议直接调用 copy / mutableCopy 程序会奔溃。拷贝协议的具体使用我这里不做扩展感兴趣的可以自行 Google 一下。有一种观点:copy 操作就是浅复制,mutableCopy 就是深复制,这是一个非常错误的理解。以下是我的一些总结:
- 可变的集合对象 + copy 得到一个新的对象(新对象不可变) 深复制
- 可变的集合对象 + mutablecopy 得到一个新的对象(新对象可变) 深复制
- 不可变集合对象 + copy 没有得到新的对象(地址的引用) 浅复制
- 不可变集合对象 + mutablecopy 得到一个新的对象(新对象可变) 深复制
怎么去动态关联一个weak属性
持有一个strong的容器,让其持有该weak属性,获取关联对象时获取其属性即可
首先,给category属性是需要使用runtime中的关联来实现set和get方法,但runtime没有提供weak ,虽然runtime没有开放weak解决方案,但objc对象是可以实现weak的,所以让需要被修饰的对象去持有一个strong对象,然后当被修饰的对象释放的时候,持有的对象也会被释放,那么我们就可以捕捉到释放的事件,进而使用OBJC_ASSOCIATION_ASSIGN来实现弱引用
对象的内存布局
struct objc_class {
Class isa;
Class super_class;
const charchar *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
} OBJC2_UNAVAILABLE;
二叉树的层序遍历
消息转发的优化
在 2020 年中,Apple 针对 Objective-C 做了三项优化
- 类数据结构变化:节约了系统更多的内存。
- 相对方法地址:节约了内存,并且提高了性能。
- Tagged Pointer 格式的变化:提高了 msgSend 性能
Self 和 this 的底层实现,是编译期还是运行期做的。答案是编译期间
this指针本质: 当一个对象调用某成员函数时编译器会隐式传入一个参数, 这个参数就是this指针
this指针中存放的就是这个对象的首地址。
其实编译器在生成程序时加入了获取对象首地址的相关代码,并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。
成员函数的其它参数正常都是存放在栈中,而this指针参数则是存放在寄存器中。
我们都知道:self 是类的隐藏参数,指向当前调用方法的这个类的实例。那 super 呢?
很多人会想当然的认为“ super 和 self 类似,应该是指向父类的指针吧!”。这是很普遍的一个误区。其实 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者!他们两个的不同点在于:super 会告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。
**OC Property **
https://juejin.cn/post/6844903735651647502
https://github.com/ChenYilong/iOSInterviewQuestions/blob/master/01%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88/%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88%EF%BC%88%E4%B8%8A%EF%BC%89.md#6-property-%E7%9A%84%E6%9C%AC%E8%B4%A8%E6%98%AF%E4%BB%80%E4%B9%88ivargettersetter-%E6%98%AF%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E5%B9%B6%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%BF%99%E4%B8%AA%E7%B1%BB%E4%B8%AD%E7%9A%84
20. 一个objc对象的isa的指针指向什么?有什么作用?
isa 顾名思义 is a 表示对象所属的类。
isa 指向他的类对象,从而可以找到对象上的方法。
同一个类的不同对象,他们的 isa 指针是一样的。
算法36进制加法
https://blog.csdn.net/lyl194458/article/details/100192501
Unicode 和 UTF-8 有什么区别?
简单来说: Unicode 是「字符集」 UTF-8 是「编码规则」 其中: 字符集:为每一个「
为什么说OC是动态语言
为什么说OC是动态语言呢?我们可以从下面几个方面来说明:
1.动态类型:即运行时再决定对象的类型,简单说就是id类型,任何对象都可以被指定为Id类型,只有在运行时才能决定是什么类型。像内置的明确的基本数据类型都属于静态类型(int,NSString等)。静态类型在编译的时候就能被识别出来,所以当程序发生了类型不对应,编译器就会发出警告。而动态类型在编译器编译的时候是不能被识别的,要等到运行时,即程序运行的时候才会根据语境来识别。所以这里就有两个概念要区分:编译时跟运行时
2.动态绑定:基于动态类型,在某个实例对象被确定之后其数据类型便被确定了,该对象的属性和响应的消息也被完全确定,这就是动态绑定。比如我们向一个NSObject对象发送-respondsToSelector:或者-instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应类的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态的向类或者实例添加新的方法,也即类的实现是可以动态绑定的;isKindOfClass也是一样的道理。
3.动态加载:所谓动态加载就是我们做开发的时候icon图片在retina设备上要多添加一个@2x的图片,当设备更换的时候图片也会自动的替换
4.多态:运行时机制是多态的基础。多态主要是将数据类型的确定由编译时推迟到了运行时。不同对象以自己的方式响应相同消息的能力叫做多态。例如所有的动物都有同一个方法eat,但每个动物的eat方式不同,也就是不同的对象以自己的方式响应了相同的信息(响应了eat这个选择器)。
Category的本质是一个_category_t结构体,其结构如下:
1、分类中只能添加“方法”,不能增加成员变量。如果分类中声明了一个属性,那么分类只会生成这个属性的set、get方法声明,也就是不会有实现。 2、分类中可以/只能访问原有类中.h中的属性。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问。 3、在本类和分类有相同的方法时,优先调用分类的方法再调用本类的方法。 4、如果多个分类中都有和原有类中同名的方法,那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
Categroy的加载过程
在编译时只是一个包含类名,类指针,方法列表,属性列表,协议列表的_category_t结构体;
在运行时通过runtime加载分类数据,把分类的方法、属性、协议数据合并到一个大数组中,后参与编译的分类会在数组的前面(i–倒数遍历数组添加的)(这也说明了分类中相同的方法后参与编译的分类会被调用);
合并后的分类数据会插入到原来类数据的前面(相同的方法,分类会优先于原来调用)。
编译顺序是可以手动设置的:TARGETS->BuildPhases->Complle Sources。(自己可以验证一下,这里不再赘述)
Category 和Class Extension 的区别
Class Extension 是在编译后合并到类中。
Category 是runtime 运行时 合并到类中。
weak 实现原理的概括
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
weak 的实现原理可以概括一下三步:
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
腾讯1
Category 在什么时候加载、为什么不能动态添加属性 关联对象关联的应该是成员变量
https://tech.meituan.com/2015/03/03/diveintocategory.html
Oc的js通信的几种方式
为什小游戏不用阿里的GCanvas
premin的流程
propoety的本质
Weak的内部实现。
https://www.jianshu.com/p/13c4fb1cedea
算法leetcode 62 不同路径
Bilibili1
Category的实现原理、关联对象的原理、加载的顺序和流程;
UIimageView加载一张图片的过程、大图片怎么优化
埋点框架
UIview和Calayer的关系
流媒体常用的协议
死锁的产生和常见场景
GCD和NS Operation
Bili2
基本问的都是项目、、没啥好提的
字节2
iOS xcodebuild后经历了哪些过程,一个oc类怎么加载的
Category的方法列表怎么加到当前class的,为什么最后一个方法的优先级最高
dispath barrier是什么,用来干嘛的
设计一个线程安全的读写 读读并发,读写互斥 写写互斥
UItableview cell复用的原理,怎么去设计一套cell复用
https://www.cnblogs.com/zhangyang17/p/3601512.html
UIView的渲染过程、渲染管线怎么工作
https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=400417748&idx=1&sn=0c5f6747dd192c5a0eea32bb4650c160&scene=0#wechat_redirect‘/ a 0 p
oc 编译过程 -objc - all_load的参数作用
字节3
描述下目前app的架构,有什么优化方向,组件化的后续发展、facebook和google怎么设计的架构和组件化
线程通信原理:
https://juejin.cn/post/6844904152082939917
runloop通信:
https://segmentfault.com/a/1190000021994646
iOS进程和进程程的通信原理,wkwebview和主进程通信原理,runloop通信的原理
消息转发、IOS系统内部对消息转发做了什么优化
Metal 和 opengl的区别,做了哪些优化
Swift 5的新特性,对应async wait原理
怎么做启动优化,怎么设计启动框架,启动线程调度和依赖怎么管理,主线程可以依赖异步线程的任务么
AOP面向切片编程在oc设计里那个场景用到了
算法题
链表交错重排
招银1
UIview和calayer
Xcode编译一个app经过的过程
携程1面
NSOperation 线程依赖的原理 如果没有这个,自己怎么实现一套线程依赖?(我回答的是信号量)
Weak实现的原理kv是什么
启动优化做了哪些事情
离屏渲染为什么会导致性能消耗
https://juejin.cn/post/6847902222567604231
怎么异步渲染一个imageView、imageView的性能优化
https://www.jianshu.com/p/7d8a82115060
https://www.jianshu.com/p/43ac91be0cf4
异步渲染主要做什么
为什么UIview层级过多会影响性能
描述下iOS里面的锁,讲一下用到锁的场景
OOM:
监控可以用didReceiveMemoryWarning
也可以类似flex ,通过malloc_get_all_zones可以获取所有堆区的对象,通过objc_getClass获取对应的对象名,通过class_getInstanceSize获取单个对象的大小。进行引用分析,获取当前内存占用
Facebook的方案是排除法,判断终止进程原因,排除已知原因
腾讯的做法是OOMDetector
可以通过malloc_logger实现对于malloc/free的监控,记录内存
AutoreleasePool与ARC的关系?
AutoreleasePool可以理解为一个对象,在ARC环境下,这个对象本身也是自动计数的,当这个pool的引用计数为0时,就被清掉了,这是手动声明时候的情况,当系统自动为我们建立AutoreleasePool以及在runloop结束时释放就是系统的事情了。但同时AutoreleasePool不同于一般的对象指针,它可以持有多个对象,当pool被release的时候,其会向其持有的所有对象发送release消息,在非ARC环境下用来延长对象的作用域是很有效的。我们知道ARC只是编译器在帮我们自动添加retain和release,而并非垃圾回收器,这样以来,就会不可避免的产生一些内存问题,
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
.a 和 .framework 的区别是什么?
.a 是单纯的二进制文件,.framework是二进制问价+资源文件。
其中.a 不能直接使用,需要 .h文件配合,而.framework则可以直接使用。
.framework = .a + .h + sorrceFile(资源文件)
RunLoop
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)
一个HTTP流程:
url - DNS查ip ,dns自己有cache,未命中再去找dns服务器 -UDP - ip -Mac地址
埋点系统设计
GCD.串行并行队列
二叉搜索树的判断
string strong copy的区别
当原字符串是NSString时,由于是不可变字符串,所以,不管使用strong还是copy修饰,都是指向原来的对象,copy操作只是做了一次浅拷贝。
而当源字符串是NSMutableString时,strong只是将源字符串的引用计数加1,而copy则是对原字符串做了次深拷贝,从而生成了一个新的对象,并且copy的对象指向这个新对象。另外需要注意的是,这个copy属性对象的类型始终是NSString,而不是NSMutableString,如果想让拷贝过来的对象是可变的,就要使用mutableCopy。 所以,如果源字符串是NSMutableString的时候,使用strong只会增加引用计数。 但是copy会执行一次深拷贝,会造成不必要的内存浪费。而如果原字符串是NSString时,strong和copy效果一样,就不会有这个问题。
一般怎么检查野指针,zombie对象怎么知道是野指针
https://www.jianshu.com/p/7bb92761f2f5
消息转发
从全局来看,消息转发机制共分为3大步骤:
1.Method resolution 方法解析处理阶段
2.Fast forwarding 快速转发阶段
3.Normal forwarding 常规转发阶段
动态卡片vm,类似字节lua
概念上类似于阿里开源的LuaView
分类为什么不能添加属性
分类添加方法的原理和顺序
- 最后添加分类的方法 new_method ,从整个方法的内存从首端开始覆盖
- 编译顺序越靠后的分类方法的优先级越高
所以在调用实例对象的方法时,会优先调用分类中的实例对象方法,具体的分类顺序需要在 XCode 中设置分类文件的编译顺序,在 Project-BuildPhases-Compile Sources 中进行设置
https://juejin.cn/post/6953474692363583525
https://fatofyoung.github.io/2018/06/13/OC%E5%88%86%E7%B1%BB%E5%8E%9F%E7%90%86/
uicontrol手势冲突
https://juejin.cn/post/6908553699732226061
怎么解决单双击冲突
requireGestureRecognizerToFail 设置手势的优先级,同样,分页控制器在左滑和系统左滑冲突时也可以这么解决
iOS 事件(UITouch、UIControl、UIGestureRecognizer)传递机制 - (jianshu.com) 聊聊NSInvocation和NSMethodSignature_Deft_MKJing的博客-CSDN博客
UITableView继承链?UITableView -> UIScrollView -> UIView -> UIResponder -> NSObject
UIresponder和UIcontrol的区别是啥?UIControl继承自UIView,UIReponder是iOS用于处理触摸事件
的基类,UIControl对其进行了深度包装,以target-action的模式进行调用。触摸事件传递流程是啥样的?分为事件传递链和响应链,传递链通过hittest函数和pointside递归的
判断子view是否可以响应事件,直到递归遍历到最后一个view,响应链则是消费事件的过程,从子 view向其的vc,superView传递触摸事件。优先级的话手势识别高于view的触摸事件,系统的 uicontrol高于手势,自定义的低于手势。如何扩大UIbutton点击范围?两种方法,重写pointinside和hittest
如何扩大手势点击范围?或者扩大一个小图片的点击范围?图片话调节内边距即可
获取当前viwe的vc方法?方法一:通过响应链机制,寻找view的下一级响应者,因为view的下一级
响应链是其vc 方法二:通过KeyWindows获取对应的rootVC一直朝下遍历,获取presetedVC知
道最后一个VC消息转发阶段流程是什么样的?具体有哪些方法?resolveMethod -> forwardingTarget -> methodSinature->forwardInvocation 第三步会获取对应的方法签名,如果能获取到可以在第四步 直接将这个方法以NSInvocation形式转发给其他对象处理
NSInvocation和NSMethodSignature的区别是啥?NSMethodSignature是方法编码过后的签名,例如 NSString的类方法isEqualToString: 的方法签名为B24@0:8@16,如下所示 @encode(BOOL) (B) 返回值 @encode(id) (@) 默认第一个参数 self
@encode(SEL) (:)默认第二个参数 _cmd
@encode(NSString ) (@) 实际上的第一个参数NSString* iOS中的method即由SEL、IMP和签名组成,SEL是method检索的方式,可以通过SEL在method list中找到对应的方法,IMP则是函数指针指向方法的本身,签名包括了函数头中的各种信息。 NSInvocation则是消息在OC中对象的形式存在,是一种更高级的转发机制可以通过添加target、 签名、参数这些强行执行方法消息转发可以做什么?怎么做的?热更新、多重代理和多继承
Runtim相关函数有哪些?贼多,建议查 Objective-C Runtime | Apple Developer Documentation
线程锁有哪些?iOS多线程安全-13种线程锁%"#$ (juejin.cn)
semaphore和nslock有啥区别?优缺点是啥?
怎么通过gcd实现读写锁?Dispatch_barrity_async
循环引用是啥?有哪些会造成?iOS解除Block循环引用,你只知道_weak就out啦知更鸟
CoolLee的博客-CSDN博客
block中的强引用是对self指针的强引用所以简单使用weak/strong就可以解决循环引用问题,但
是NSTimer中的循环引用是对整个对象的强引用NStimer循环引用是怎么造成?怎么解决?NSTimer会强引用整个对象,对象持有Timer就会引起强
引用。方法1:及时结束Timer运行,使用invalidata结束运行并置整个Timer为nil 方法2:target不指向自身,指向一个其他对象 方法3:使用NSProxy替代self,消息转发阶段转发消息回原类NSProxy是啥?有啥用?NSProxy是一个等同于NSObject的基类,实现了
的协议,自身没 有任何实现,主要用于转发消息的基类,可以继承自这个基类,实现消息转发中的方法可以将消 息转发给其他对象。可以用于实现oc中本不支持的多继承,解决NSTimer中的循环引用。
NSProxy和NSObject的区别?
-
虽然都需要实现了
协议,主要差别在消息转发流程中, NSObject会走完完整的消息转发机制,NSProxy直接回调-methodSignatureForSelector:/- forwardInvocation:,消息转发过程比class NSObject要简单得多,NSProxy会将自省相关的selector
直接forward到-forwardInvocation:回调中,例如 - (BOOL)isKindOfClass:(Class)aClass;- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector;
_cmd是啥?表示这个方法本身
block如何获取外部变量?
+load方法和initialize方法加载顺序?
IOSkeychain
Socket 场链接 内购 gcd
如何捕获**crash **
https://www.jianshu.com/p/5fcf7bb7955f
动态库和静态库
block 为什么用copy修饰 Block实现原理
https://juejin.cn/post/6844904040954871815
setObject:forKey:和setValue:forKey:的
kvc 和kvo
kvc set:简单来说就是如果没有找到Set
当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方***负责在调用原 setter方法之前和之后,通知所有观察对象值的更改。最后把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。
原来,这个中间类,继承自原本的那个类。不仅如此,Apple 还重写了 -class 方法,企图欺骗我们这个类没有变,就是原本那个类。更具体的信息,去跑一下 Mike Ash 的那篇文章里的代码就能明白,这里就不再重复。
https://juejin.cn/post/6844903602545229831
介绍下oc
RunTime:
首先 OC 是 C 语言的超集,因为 runtime 这个库使得C语言有了面向对象的能力:
OC 对象可以用C语言中的结构体表示,而方法可以用C函数来实现,这些结构体和函数被 runtime 函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
OC 是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。
这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。这个运行时系统即Objc Runtime。Objc Runtime基本上是用C和汇编写的。
https://www.jianshu.com/p/d7818dcb21de
静态库和动态库:
https://juejin.cn/post/7040003550977458207
编译和链接:
http://www.360doc.com/content/17/0111/22/32626470_621879084.shtml
集合类型 copy 操作和 mutableCopy 操作
一个类遵循 NSCopying, NSMutableCopying 协议并且实现相对应的初始化方法后,这个类就具有对象拷贝的能力。如果你自定义类没有遵守协议直接调用 copy / mutableCopy 程序会奔溃。拷贝协议的具体使用我这里不做扩展感兴趣的可以自行 Google 一下。有一种观点:copy 操作就是浅复制,mutableCopy 就是深复制,这是一个非常错误的理解。以下是我的一些总结:
- 可变的集合对象 + copy 得到一个新的对象(新对象不可变) 深复制
- 可变的集合对象 + mutablecopy 得到一个新的对象(新对象可变) 深复制
- 不可变集合对象 + copy 没有得到新的对象(地址的引用) 浅复制
- 不可变集合对象 + mutablecopy 得到一个新的对象(新对象可变) 深复制
怎么去动态关联一个weak属性
持有一个strong的容器,让其持有该weak属性,获取关联对象时获取其属性即可
首先,给category属性是需要使用runtime中的关联来实现set和get方法,但runtime没有提供weak ,虽然runtime没有开放weak解决方案,但objc对象是可以实现weak的,所以让需要被修饰的对象去持有一个strong对象,然后当被修饰的对象释放的时候,持有的对象也会被释放,那么我们就可以捕捉到释放的事件,进而使用OBJC_ASSOCIATION_ASSIGN来实现弱引用
对象的内存布局
struct objc_class {
Class isa;
Class super_class;
const charchar *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
} OBJC2_UNAVAILABLE;
二叉树的层序遍历
消息转发的优化
在 2020 年中,Apple 针对 Objective-C 做了三项优化
- 类数据结构变化:节约了系统更多的内存。
- 相对方法地址:节约了内存,并且提高了性能。
- Tagged Pointer 格式的变化:提高了 msgSend 性能
Self 和 this 的底层实现,是编译期还是运行期做的。答案是编译期间
this指针本质: 当一个对象调用某成员函数时编译器会隐式传入一个参数, 这个参数就是this指针
this指针中存放的就是这个对象的首地址。
其实编译器在生成程序时加入了获取对象首地址的相关代码,并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。
成员函数的其它参数正常都是存放在栈中,而this指针参数则是存放在寄存器中。
我们都知道:self 是类的隐藏参数,指向当前调用方法的这个类的实例。那 super 呢?
很多人会想当然的认为“ super 和 self 类似,应该是指向父类的指针吧!”。这是很普遍的一个误区。其实 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者!他们两个的不同点在于:super 会告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。
**OC Property **
https://juejin.cn/post/6844903735651647502
https://github.com/ChenYilong/iOSInterviewQuestions/blob/master/01%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88/%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88%EF%BC%88%E4%B8%8A%EF%BC%89.md#6-property-%E7%9A%84%E6%9C%AC%E8%B4%A8%E6%98%AF%E4%BB%80%E4%B9%88ivargettersetter-%E6%98%AF%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E5%B9%B6%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%BF%99%E4%B8%AA%E7%B1%BB%E4%B8%AD%E7%9A%84
20. 一个objc对象的isa的指针指向什么?有什么作用?
isa 顾名思义 is a 表示对象所属的类。
isa 指向他的类对象,从而可以找到对象上的方法。
同一个类的不同对象,他们的 isa 指针是一样的。
算法36进制加法
https://blog.csdn.net/lyl194458/article/details/100192501
Unicode 和 UTF-8 有什么区别?
简单来说: Unicode 是「字符集」 UTF-8 是「编码规则」 其中: 字符集:为每一个「
为什么说OC是动态语言
为什么说OC是动态语言呢?我们可以从下面几个方面来说明:
1.动态类型:即运行时再决定对象的类型,简单说就是id类型,任何对象都可以被指定为Id类型,只有在运行时才能决定是什么类型。像内置的明确的基本数据类型都属于静态类型(int,NSString等)。静态类型在编译的时候就能被识别出来,所以当程序发生了类型不对应,编译器就会发出警告。而动态类型在编译器编译的时候是不能被识别的,要等到运行时,即程序运行的时候才会根据语境来识别。所以这里就有两个概念要区分:编译时跟运行时
2.动态绑定:基于动态类型,在某个实例对象被确定之后其数据类型便被确定了,该对象的属性和响应的消息也被完全确定,这就是动态绑定。比如我们向一个NSObject对象发送-respondsToSelector:或者-instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应类的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态的向类或者实例添加新的方法,也即类的实现是可以动态绑定的;isKindOfClass也是一样的道理。
3.动态加载:所谓动态加载就是我们做开发的时候icon图片在retina设备上要多添加一个@2x的图片,当设备更换的时候图片也会自动的替换
4.多态:运行时机制是多态的基础。多态主要是将数据类型的确定由编译时推迟到了运行时。不同对象以自己的方式响应相同消息的能力叫做多态。例如所有的动物都有同一个方法eat,但每个动物的eat方式不同,也就是不同的对象以自己的方式响应了相同的信息(响应了eat这个选择器)。
Category的本质是一个_category_t结构体,其结构如下:
1、分类中只能添加“方法”,不能增加成员变量。如果分类中声明了一个属性,那么分类只会生成这个属性的set、get方法声明,也就是不会有实现。 2、分类中可以/只能访问原有类中.h中的属性。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问。 3、在本类和分类有相同的方法时,优先调用分类的方法再调用本类的方法。 4、如果多个分类中都有和原有类中同名的方法,那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
Categroy的加载过程
在编译时只是一个包含类名,类指针,方法列表,属性列表,协议列表的_category_t结构体;
在运行时通过runtime加载分类数据,把分类的方法、属性、协议数据合并到一个大数组中,后参与编译的分类会在数组的前面(i–倒数遍历数组添加的)(这也说明了分类中相同的方法后参与编译的分类会被调用);
合并后的分类数据会插入到原来类数据的前面(相同的方法,分类会优先于原来调用)。
编译顺序是可以手动设置的:TARGETS->BuildPhases->Complle Sources。(自己可以验证一下,这里不再赘述)
Category 和Class Extension 的区别
Class Extension 是在编译后合并到类中。
Category 是runtime 运行时 合并到类中。
weak 实现原理的概括
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
weak 的实现原理可以概括一下三步:
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。