1、kvo底层实现cell中一个点赞功能如果用kvo需要注意什么?(提示涉及cell复用问题)
2、UIView和layer的关系,组合关系,为什么不做成继承?两种方式各有什么利弊?
3、Swift用过没?它就使用了面向协议?
4、显式动画,隐式动画平时哪里使用多线程?要注意什么?
5、AFNetworking怎么实现线程保活?
6、reachability如何检测到网络状态变化?
iOS下的实际网络连接状态检测:RealReachability
7、渲染UI为什么要在主线程?
8、FB那个Async库都做了什么?消息转发,哪些步骤能被利用?
9、算法:一个数组,有个滑动窗口,求每次窗口中的中位数。
iOS基础
1:讲讲你对atomic 和noatomic的理解
2:被 weak 修饰的对象在被释放的时候会发生什么?是如何实现的?知道sideTable 么?里面的结构可以画出来么?
3:block 用什么修饰?strong 可以?
4:block 为什么能够捕获外界变量? __block做了什么事?
5:谈谈你对事件的传递链和响应链的理解 (这个面试题,如果求职者能够回答一些实际开发相关的处理,不只是简单的概念,予以加分)
6:谈谈 KVC 以及 KVO 的理解?
7:RunLoop 的作用是什么?它的内部工作机制了解么?
8:苹果是如何实现 autoreleasepool的?
9:谈谈你对 FRP (函数响应式) 的理解,延伸一下 RxSwift 或者 RAC!
10:平时开发有没有玩过 Instrument ?
Runtime
1:什么是 isa,isa 的作用是什么?
2:一个实例对象的isa 指向什么?类对象指向什么?元类isa 指向什么?
3:objc 中类方法和实例方法有什么本质区别和联系?
4:load 和 initialize 的去呗?
5:_objc_msgForward 函数是做什么的?直接调用会发生什么问题?
6:简述下 Objective-C 中调用方法的过程
7:能否想向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
iOS基础
1.1、讲讲你对atomic 和noatomic的理解
-
1、原子操作对线程安全并无任何安全保证。被 atomic 修饰的属性(不重载设置器和访问器)只保证了对数据读写的完整性,也就是原子性,但是与对象的线程安全无关。
-
2、线程安全有保障、对性能有要求的情况下可使用 nonatomic替代atomic,当然也可以一直使用atomic。
-
3、实现:
原子性不可能由软件单独保证--必须需要硬件的支持,因此是和架构相关的。在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。
1.2、被 weak 修饰的对象在被释放的时候会发生什么?是如何实现的?知道sideTable 么?里面的结构可以画出来么
-
被weak修饰的对象在被释放时候会置为nil,不同于assign;
-
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
-
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
-
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
-
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
struct SideTable {
// 保证原子操作的自旋锁
spinlock_t slock;
// 引用计数的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了所有指向指定对象的 weak 指针
weak_entry_t *weak_entries;
// 存储空间
size_t num_entries;
// 参与判断引用计数辅助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};
1.3、block 用什么修饰?strong 可以
- block 本身是像对象一样可以 retain,和 release。但是,block 在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。
- 使用 retain 也可以,但是block的retain行为默认是用copy的行为实现的。因为 block 变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把 block 拷贝(copy)到堆,所以说为了 block 属性声明和实际的操作一致,最好声明为 copy。
auto变量的捕获
image.pngBlock的类型
image.png image.png对象类型的auto变量
image.png__block修饰符
image.png__block的内存管理
image.png image.png对象类型的auto变量、__block变量
image.png- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
MJPerson *p = [[MJPerson alloc] init];
__weak MJPerson *weakP = p;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1-------%@", p);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"2-------%@", weakP);
});
});
NSLog(@"touchesBegan:withEvent:");
}
测试结果:
touchesBegan:withEvent:
1-------<MJPerson: 0x6000037984e0>
MJPerson - dealloc
2-------(null)
1.5:谈谈你对事件的传递链和响应链的理解
1、史上最详细的iOS之事件的传递和响应机制-原理篇
2、iOS响应者链、事件的传递
1.6、谈谈 KVC 以及 KVO 的理解?
image.png image.png1.7、RunLoop 的作用是什么?它的内部工作机制了解么?
image.png image.pngRunLoop与线程
image.pngRunLoop相关的类
image.pngCFRunLoopModeRef
image.pngCFRunLoopObserverRef
image.pngRunLoop的运行逻辑
image.png image.png1.8、苹果是如何实现 autoreleasepool的
Autoreleasepool所使用的数据结构是什么?AutoreleasePoolPage结构体了解么
arc下编译器会优化成
void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);
- 向一个结构AutoreleasePoolPage,中写入需要自动释放的对象,类似一种标记,调用objc_autoreleasePoolPop(context)后,就会把这中间的对象release一下。
- 这里要注意的是,方法返回值是怎么做到自动释放的?其使用Thread Local Storage(TLS)线程局部存储,每次存入线程或者从线程取出来。
- 我们没有卸载{}中的自动释放对象,会在每个runloop结束时候去释放,相当于一个大的autoreleasepool中。
AutoreleasePoolPage的结构
image.png image.pngRunloop和Autorelease
image.png1.9、谈谈你对 FRP (函数响应式) 的理解,延伸一下 RxSwift 或者 RAC!
参考文章:RxSwift(1)— 初探 看这一篇文章也就够了!然后结合 RxSwift 映射到 RAC!函数响应式的思想是不变的!至于内部的封装有所不同,但是最终却是殊途同归!
1.10、平时开发有没有玩过 Instrument
Runtime
1.1、什么是 isa,isa 的作用是什么?
image.png image.pngClass的结构
image.png1.2、isa、superclass总结
image.png1.3、load 和 initialize 的区别?
+load
- 1、只要程序启动就会将所有类的代码加载到内存中(在main函数执行之前), 放到代码区(无论该类有没有被使用到都会被调用)
- 2、+load方法会在当前类被加载到内存的时候调用, 有且仅会调用一次
- 3、当父类和子类都实现+load方法时, 会先调用父类的+load方法, 再调用子类的+load方法
- 4、先加载原始类,再加载分类的+load方法
- 5、当子类未实现+load方法时,不会调用父类的+load方法
- 6、多个类都实现+load方法,+load方法的调用顺序,与Compile Sources中出现的顺序一致
+initialize
- 1、当类第一次被使用的时候就会调用(创建类对象的时候)
- 2、initialize方法在整个程序的运行过程中只会被调用一次, 无论你使用多少次这个类都只会调用一次
- 3、initialize用于对某一个类进行一次性的初始化
- 4、先调用父类的initialize再调用子类的initialize
- 5、当子类未实现initialize方法时,会把父类的实现继承过来调用一遍,再次之前父类的initialize方法会被优先调用一次
- 6、当有多个Category都实现了initialize方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个Category 的initialize方法)
1.4、_objc_msgForward 函数是做什么的?直接调用会发生什么问题?
当对象没有实现某个方法 ,会调用这个函数进行方法转发。某方法对应的IMP没找到,会返回这个函数的IMP去执行)
- 1.调用resolveInstanceMethod:方法,允许用户在此时为该Class动态添加实现。如果有实现了,则调用并返回。如果仍没实现,继续下面的动作。
- 2.调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接转发给它。如果返回了nil,继续下面的动作。
- 3.调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。
- 4.调用forwardInvocation:方法,将地3步获取到的方法签名包装成Invocation传入,如何处理就在这里面了。
如果直接调用这个方法,就算实现了想调用的方法,也不会被调用,会直接走消息转发步骤。
1.5、简述下 Objective-C 中调用方法的过程
image.png image.png image.pngimage.png image.png
1.6、能否想向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
- 1.不能向编译后得到的类增加实例变量
- 2.能向运行时创建的类中添加实例变量
解释:
- 1.编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定, runtime会调用 class_setvarlayout 或 class_setWeaklvarLayout来处理 strong weak引用.所以不能向存在的类中添加实例变量
- 2.运行时创建的类是可以添加实例变量,调用class_addIvar函数.但是的在调用objc_allocateClassPair之后, objc_registerClassPair之前,原因同上.
网友评论