[iOS知识简记]-题库走查1

https://www.jianshu.com/p/75e4b9fdcf41
这里的题库走查。

算法

6 如何查找两个子视图的共同父视图?
给的解法不是最优,可以不利用数组记录所有父节点,直接遍历算长度就可以。
类似找2个单向链表的公共节点,算2个链表的长度,做差,然后长链表偏移后同时遍历。
8 如何给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
给的解法不是最优,可以先排序,然后再O(n)量级的左右两边向内遍历求和。

内存管理

5 @protocol和category中如何使用@property
在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,
我们使用属性的目的,是希望遵守我协议的对象能实现该属性。
category 使用 @property 也是只会生成 setter 和 getter 方法的声明,
如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
objc_setAssociatedObject和objc_getAssociatedObject。
6 BAD_ACCESS在什么情况下出现?
给的答案都不够本质和底层。
8 iOS内存管理方式
has_sidetable_rc/extra_rc/SideTables等细看
10 ARC 的 retainCount 怎么存储的?
存在64张哈希表中,根据哈希算法去查找所在的位置,无需遍历,十分快捷。
散列表(引用计数表、weak表):
SideTables 表在 非嵌入式的64位系统中,有 64张 SideTable 表
每一张 SideTable 主要是由三部分组成。自旋锁、引用计数表、弱引用表。
全局的 引用计数 之所以不存在同一张表中,是为了避免资源竞争,解决效率的问题。
引用计数表 中引入了 分离锁的概念,将一张表分拆成多个部分,对他们分别加锁,可以实现并发操作,
提升执行效率:
引用计数表(哈希表)
通过指针的地址,查找到引用计数的地址,大大提升查找效率
通过 DisguisedPtr(objc_object) 函数存储,同时也通过这个函数查找,这样就避免了循环遍历。

消息传递的方式

1 KVC的实现原理
KVC,键-值编码,使用字符串直接访问对象的属性。
底层实现,当一个对象调用setValue方法时,方法内部会做以下操作:
检查是否存在相应key的set方法,如果存在,就调用set方法
如果set方法不存在,就会查找与key相同名称并且带下划线的成员属性,如果有,则直接给成员属性赋值
如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值
如果还没找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法
2 KVO的实现原理
1.当给A类添加KVO的时候,runtime动态的生成了一个子类NSKVONotifying_A,
让A类的isa指针指向NSKVONotifying_A类,重写class方法,隐藏对象真实类信息
2.重写监听属性的setter方法,在setter方法内部调用了Foundation 的 
_NSSetObjectValueAndNotify 函数
3._NSSetObjectValueAndNotify函数内部
a) 首先会调用 willChangeValueForKey
b) 然后给属性赋值
c) 最后调用 didChangeValueForKey
d) 最后调用 observer 的 observeValueForKeyPath 去告诉监听器属性值发生了改变 .
4.重写了dealloc做一些 KVO 内存释放
6 为什么Block用copy关键字?
Block在没有使用外部变量时,内存存在全局区,然而,当Block在使用外部变量的时候,
内存是存在于栈区,当Block copy之后,是存在堆区的。
存在于栈区的特点是对象随时有可能被销毁,一旦销毁在调用的时候,就会造成系统的崩溃。
所以Block要用copy关键字。
------ ARC后,还有几个存放在栈区的???所以也不关键了吧???

动画

1 UIView动画与核心动画的区别?
核心动画只作用在layer.
核心动画修改的值都是假像.它的真实位置没有发生变化.
当需要与用户进行交互时用UIView动画,不需要与用户进行交互时两个都可以.
2 当我们要做一些基于 CALayer 的动画时,有时需要设置 layer 的锚点来配合动画,这时候我们需要注意什么?
需要注意的是设置锚点会引起原来 position 的变化,可能会发生不符合预期的行为,
所以要做一下转化,示例代码如下

Runtime

1 Category 的实现原理?
Category 实际上是 Category_t的结构体,在运行时,新添加的方法,
都被以倒序插入到原有方法列表的最前面,所以不同的Category,添加了同一个方法,
执行的实际上是最后一个。
Category 在刚刚编译完的时候,和原来的类是分开的,只有在程序运行起来后,
通过 Runtime ,Category 和原来的类才会合并到一起。
2 isa指针的理解,对象的isa指针指向哪里?isa指针有哪两种类型?
isa 等价于 is kind of
实例对象的 isa 指向类对象
类对象的 isa 指向元类对象
元类对象的 isa 指向元类的基类
isa 有两种类型
纯指针,指向内存地址
NON_POINTER_ISA,除了内存地址,还存有一些其他信息
4 runtime 如何实现 weak 属性?
weak 此特质表明该属性定义了一种「非拥有关系」(nonowning relationship)。
为这种属性设置新值时,设置方法既不持有新值(新指向的对象),也不释放旧值(原来指向的对象)。
runtime 对注册的类,会进行内存布局,从一个粗粒度的概念上来讲,这时候会有一个 hash 表,
这是一个全局表,表中是用 weak 指向的对象内存地址作为 key,
用所有指向该对象的 weak 指针表作为 value。当此对象的引用计数为 0 的时候会 dealloc,
假如该对象内存地址是 a,那么就会以 a 为 key,在这个 weak 表中搜索,
找到所有以 a 为键的 weak 对象,从而设置为 nil。
runtime 如何实现 weak 属性具体流程大致分为 3 步:
1、初始化时:runtime 会调用 objc_initWeak 函数,初始化一个新的 weak 指针指向对象的地址。
2、添加引用时:objc_initWeak 函数会调用 objc_storeWeak() 函数,
objc_storeWeak() 的作用是更新指针指向(指针可能原来指向着其他对象,
这时候需要将该 weak 指针与旧对象解除绑定,会调用到 weak_unregister_no_lock),
如果指针指向的新对象非空,则创建对应的弱引用表,将 weak 指针与新对象进行绑定,
会调用到 weak_register_no_lock。在这个过程中,为了防止多线程中竞争冲突,
会有一些锁的操作。
3、释放时:调用 clearDeallocating 函数,clearDeallocating 函数首先根据对象地址
获取所有 weak 指针地址的数组,然后遍历这个数组把其中的数据设为 nil,
最后把这个 entry 从 weak 表中删除,最后清理对象的记录。
7 runtime如何通过selector找到对应的IMP地址?
每一个类对象中都一个对象方法列表(对象方法缓存)
类方法列表是存放在类对象中isa指针指向的元类对象中(类方法缓存)。
方法列表中每个方法结构体中记录着方法的名称,方法实现,以及参数类型,
其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现。
当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找。
当我们发送一个消息给一个类时,这条消息会在类的Meta Class对象的方法列表里查找。
9 load和initialize的区别
load和initialize方法都不用显示的调用父类的方法而是自动调用,
即使子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类。
------ TODO:确认下

------ Runtime分类里好多答案都过于简单粗糙。

项目架构

1 MVC、MVP、MVVM模式
MVP(Model、View、Presenter)
View与MVC中的View层有一些差别,MVP中的View层可以是viewController、view等控件;
Presenter层则是作为Model和View的中介,从Model层获取数据之后传给View。
从上图可以看出,从MVC模式中增加了Presenter层,将UIViewController中复杂的业务逻辑、
网络请求等剥离出来。
MVVM(Model、Controller/View、ViewModel)
在MVVM中,view和ViewCOntroller联系在一起,我们把它们视为一个组件,
view和ViewController都不能直接引用model,而是引用是视图模型即ViewModel。 
viewModel是一个用来放置用户输入验证逻辑、视图显示逻辑、网络请求等业务逻辑的地方,
这样的设计模式,会轻微增加代码量,但是会减少代码的复杂性
2 关于RAC你有怎样运用到解决不同API依赖关系
信号的依赖:使用场景是当信号A执行完才会执行信号B,和请求的依赖很类似,
例如请求A请求完毕才执行请求B,我们需要注意信号A必须要执行发送完成信号,否则信号B无法执行
3 @weakify和我们宏定义的WeakSelf有什么区别?
@weakify 可以多参数使用

------ 项目架构分类里的题目都是解决的一些局部问题或某小类问题,架构过小。

设计模式

3 编程中的六大设计原则?
1.单一职责原则
通俗地讲就是一个类只做一件事
CALayer:动画和视图的显示。
UIView:只负责事件传递、事件响应。
2.开闭原则
对修改关闭,对扩展开放。 要考虑到后续的扩展性,而不是在原有的基础上来回修改
3.接口隔离原则
使用多个专门的协议、而不是一个庞大臃肿的协议,
如 UITableviewDelegate + UITableViewDataSource
4.依赖倒置原则
抽象不应该依赖于具体实现、具体实现可以依赖于抽象。 调用接口感觉不到内部是如何操作的
5.里氏替换原则
父类可以被子类无缝替换,且原有的功能不受任何影响 如:KVO
6.迪米特法则
一个对象应当对其他对象尽可能少的了解,实现高聚合、低耦合

组件化

3 为什么CTMediator方案优于基于Router的方案?
4 基于CTMediator的组件化方案,有哪些核心组成?

iOS关于CTMediator组件化实践的详解篇
https://www.jianshu.com/p/b1c6d070c92b

性能优化

5 如何检测离屏渲染与优化
检测,通过勾选Xcode的Debug->View Debugging-->Rendering->Run
->Color Offscreen-Rendered Yellow项。
优化,如阴影,在绘制时添加阴影的路径
6 怎么检测图层混合

持续集成

1 你在项目中使用过什么持续集成方式?
Fastlane:一套用Ruby写的自动化工具集,可用于iOS和Android的打包、发布,节省了大量时间。
Fastlane配置比较简单,主要编写集成的lane,然后在命令行操作即可
Jenkins:Jenkins比较受欢迎,插件众多,但对新手来说配置可能稍微麻烦点。

Foundation

5 id 和 instanceType 有什么区别?
相同点
instancetype 和 id 都是万能指针,指向对象。
不同点:
1.id 在编译的时候不能判断对象的真实类型,
instancetype 在编译的时候可以判断对象的真实类型。
2.id 可以用来定义变量,可以作为返回值类型,可以作为形参类型;
instancetype 只能作为返回值类型。
6 self和super的区别
self调用自己方法,super调用父类方法
self是类,super是预编译指令
[self class] 和 [super class] 输出是一样的
self和super底层实现原理
1.当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;
而当使用 super 时,则从父类的方法列表中开始找,然后调用父类的这个方法
2.当使用 self 调用时,会使用 objc_msgSend 函数:
 id objc_msgSend(id theReceiver, SEL theSelector, ...)
第一个参数是消息接收者,第二个参数是调用的具体类方法的 selector,
后面是 selector 方法的可变参数。以 [self setName:] 为例,
编译器会替换成调用 objc_msgSend 的函数调用,其中 theReceiver 是 self,
theSelector 是 @selector(setName:),这个 selector 是从当前 self 的 
class 的方法列表开始找的 setName,当找到后把对应的 selector 传递过去。
3.当使用 super 调用时,会使用 objc_msgSendSuper 函数:
  id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一个参数是个objc_super的结构体,第二个参数还是类似上面的类方法的selector
struct objc_super {
    id receiver;
    Class superClass;
};
------ TODO:反汇编看下
7 @synthesize和@dynamic分别有什么作用?
@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。
如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,
那么编译器会自动为你加上这两个方法。
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。
(当然对于 readonly 的属性只需提供 getter 即可)。
假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,
编译的时候没问题,但是当程序运行到 instance.var = someVar,
由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,
由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,
这就是所谓的动态绑定。

底层xxx

1 一个 NSObject 对象占用多少内存空间?
受限于内存分配的机制,一个 NSObject对象都会分配 16byte 的内存空间。
但是实际上在 64位 下,只使用了 8byte;
在32位下,只使用了 4byte
一个 NSObject 实例对象成员变量所占的大小,实际上是 8 字节
#import <Objc/Runtime>
Class_getInstanceSize([NSObject Class])
本质是
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
获取 Obj-C 指针所指向的内存的大小,实际上是16 字节
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj); 
对象在分配内存空间时,会进行内存对齐,所以在 iOS 中,分配内存空间都是 16字节 的倍数。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值