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
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。