iOS面试题整理

1、数组去重的方法:

(1)原来集合操作可以通过valueForKeyPath来实现的,去重可以一行代码实现(顺序不发生变化)

(2)利用NSDictionary去重,字典在设置key-value时,若已存在则更新值,若不存在则插入值,然后获取allValues。若不要求有序,则可以采用此种方法。若要求有序,还得进行排序(使用sortedArrayusingcomparator)

(3)利用集合NSSet的特性(确定性、无序性、互异性),放入集合就自动去重了。但是它与字典拥有同样的无序性,所得结果顺序不再与原来一样。如果不要求有序,使用此方法与字典的效率应该是差不多的

(4)[NSOrderedset orderedsetwitharray:arr].array 

2、runtime,runloop,block,kvo,kvc,gcd 底层原理、 iOS编译原理,编译流程、发起一次http或者https的整个流程

3、iOS Runtime的实际应用

1)动态给分类添加属性 2)方法的交换swizzling 3)字典转模型4)获取所有的私有属性和方法5)对私有属性修改6)归档:解档7)动态的添加方法

4、一次完整的HTTP请求过程

对www.baidu.com这个网址进行DNS域名解析,得到对应的IP地址

根据这个IP,找到对应的服务器,发起TCP的三次握手

建立TCP连接后发起HTTP请求

服务器响应HTTP请求,浏览器得到html代码

浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)(先得到html代码,才能去找这些资源)

浏览器对页面进行渲染呈现给用户

服务器关闭关闭TCP连接

5、KVO

当某个类的实例对象的key第一次被观察时,系统就会在运行期动态地

创建该类的一个派生类NSKVONotifying_类名,

在这个派生类中重写该类中被观察的属性的 setter 方法。

5.1 当调用addObserver函数的时候,系统运行时自动帮你把Animal类替换为了 NSKVONotifying_Animal类,同时重写了set方法,当我们查看addObserver函数的时候,可以看到该函数在NSObject分类下@interfaceNSObject(NSKeyValueObserverRegistration)

作者:roger_Hunter

链接:https://www.jianshu.com/p/91c41292b5b9

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6、Runtime 的作用

Objc 在三种层面上与 Runtime 系统进行交互:

通过 Objective-C 源代码

通过 Foundation 框架的 NSObject 类定义的方法

通过对 Runtime 库函数的直接调用

作者:sheldon_龙

链接:https://www.jianshu.com/p/735a9ed7062f

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

7、__weak 在指向的内存销毁后,可以将指针变量置为 nil,这样更加安全。

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

2、添加引用时:objc_initWeak函数会调用objc_storeWeak()函数,objc_storeWeak()的作用是更新指针指向,创建对应的弱引用表。

3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

作者:Liberalism

链接:https://www.jianshu.com/p/0d7dfb5093a8

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

8、如何打破循环引用?

注意变量作用域,使用 autorelease 让编译器来处理引用。

使用弱引用(__weak)。

当实例变量完成工作后,将其置为 nil。

9、autoReleasePool什么时候释放?

App启动后,苹果在主线程RunLoop里注册了两个Observer,其回调都是_wrapRunLoopWithAutoreleasePoolHandler()。

第一个Observer监视的事件是Entry(即将进入Loop),其回调内会调用_objc_autoreleasePoolPush()创建自动释放池。其order是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。

第二个Observer监视了两个事件:BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()释放旧的池并创建新池;Exit(即将退出Loop) 时调用_objc_autoreleasePoolPop()来释放自动释放池。这个Observer的order是2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。

在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被RunLoop创建好的AutoreleasePool环绕着,所以不会出现内存泄漏,开发者也不必显示创建Pool了。

作者:Liberalism

链接:https://www.jianshu.com/p/0d7dfb5093a8

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

10、Block从栈中复制到堆

调用Block的copy实例方法时

Block作为函数返回值返回时

在带有usingBlock的Cocoa方法或者GCD的API中传递Block时候

将block赋给带有__strong修饰符的id类型或者Block类型时

作者:小凉介

链接:https://www.jianshu.com/p/221d0778dcaa

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

11、如标题首先需要注册    [self.wkWebView.configuration.userContentController addScriptMessageHandler:self name:@"方法名"];

didReceiveScriptMessage方法进行监听

H5只需要一行代码:window.webkit.messageHandlers.方法名.postMessage(null);//ps: 小括号里的null或者说是参数一定要写,否则iOS这点不会有回调。

12、1、+load方法是在加载类和分类时系统调用,一般不手动调用,如果想要在类或分类加载时做一些事情,可以重写类或者分类的+load方法方法。

2、每个类、分类的+load,在程序运行过程中只调用一次。

调用顺序

1、类要优先于分类调用+load方法;

2、子类调用+load方法时,要先要调用父类的+load方法;(父类优先与子类,与继承不同);

3、不同的类按照编译先后顺序调用+load方法(先编译,先调用);

4、分类的按照编译先后顺序调用+load方法(先编译,先调用)。

call_class_loads(),call_category_loads() ;看到这两个函数想到了什么呢?

对,就是这两个函数决定了类优先与分类调用+load方法;

说明:+load方法是系统根据方法地址直接调用,并不是objc_msgSend函数调用(isa,superClass);这就决定了如果子类没有实现+load方法,那么当它被加载时runtime是不会调用父类的+load方法的,除非父类也实现了+load方法;

作者:吕建雄

链接:https://www.jianshu.com/p/7a4162f59991

https://www.jianshu.com/p/e6979a17da91

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

13、iOS @autoreleasepool是什么?什么时候用?什么时候释放?

一是Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop。

二是手动调用AutoreleasePool的释放方法(drain方法)来销毁AutoreleasePool

对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。

那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 都会是一个新的Runloop。

作者:GabrielPanda

链接:https://www.jianshu.com/p/405b8dfc3829

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

14、https://www.jianshu.com/p/d0aab0eb8ce4    iOS实时卡顿检测-RunLoop(附实例)  https://github.com/chenshuangsmart/CatonMonitor/tree/master/PerformanceMonitor

15、tableView的内存/性能优化和iOS性能优化?

       答:tableView内存优化核心思想是:

       1、cell的复用机制,在使用cell时,只会创建一屏幕多一个的cell,例如:如果一屏幕能装下10个cell,系统只需要创建11个cell,当显示第11个cell时,第一个cell正在失去焦点,当滑动到第12个cell时,第一个cell已经完全失去焦点,放在缓存池等待复用。此时第12个cell就会使用cellIdentifier标识去缓存池中寻找相对应的cell,如果存在,就不用创建新的cell,直接从缓存池中取出来重新赋值。这样做的目的是为了防止cell创建过多浪费内存。

       2、cell滑动时数据( 图片)按需加载,在cell数据过于庞大时,快速滑动很容易造成页面卡桢,对此问题,我首先想到的是数据的异步加载,但异步加载在滑动时,操作依然会被执行,开启线程过多时,对整个app的性能也会造成很大的影响。

       此时可以利用父类UIScrollView的两个代理来解决这个问题。

方法一:- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate(此方法在停止拖拽时执行)

方法二:- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView(此方法在减速停止时执行)

       可利用此方法在tableView停止滑动时,进行图片加载。加载前,调用 indexPathsForVisibleRows或者visibleCells遍历出可见部分的indexPath数组或者cell数组,然后按需加载。

也可以在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中通过截取tableView的当前状态来进行图片异步加载操作。

作者:马威明

链接:https://www.jianshu.com/p/4158c73690db

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(iOS面试题整理)