知识点
二进制底层
https://www.bilibili.com/video/av80851434/
70m
0:底层概述(OC本质、KVC、KVO、Categroy、Block)
https://juejin.im/post/5d5bd09af265da039b249bef#heading-12
1:runloop 相关
https://juejin.im/post/5cb745dde51d456e6479b463
2:runtime 相关
https://juejin.im/post/5d9f3dbc6fb9a04e0926092d
3:多线程
https://juejin.im/post/5d9f3eb0e51d4577ec4eb977
架构
https://juejin.im/post/5d9f3f0af265da5b7a7544b2
网络相关
https://juejin.im/post/5d61fc046fb9a06aef08f545#heading-19
对象销毁
// 对象的内存销毁时间表
- 调用 -release :引用计数变为零
- 对象正在被销毁,生命周期即将结束.
- 不能再有新的 __weak 弱引用, 否则将指向 nil.
- 调用 [self dealloc]
- 子类 调用 -dealloc
- 继承关系中最底层的子类 在调用 -dealloc
- 如果是 MRC 代码 则会手动释放实例变量们(iVars)
- 继承关系中每一层的父类 都在调用 -dealloc
- NSObject 调 -dealloc
- 只做一件事:调用 Objective-C runtime 中的 object_dispose() 方法
- 调用 object_dispose()
- 为 C++ 的实例变量们(iVars)调用 destructors
- 为 ARC 状态下的 实例变量们(iVars) 调用 -release
- 解除所有使用 runtime Associate方法关联的对象
- 解除所有 __weak 引用
- 调用 free()
那么为什么明明调用了 super 这个关键字 返回的[super class] 还是 Student 呢 ?
通过上边代码可知 , [super class] 最终编译器转化成了 objc_msgSendSuper(struct objc_super *,SEL) ,其中
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
if !defined(__cplusplus) && !OBJC2
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
else
__unsafe_unretained _Nonnull Class super_class;
endif
/* super_class is the first class to search */
};
endif
复制代码objc_super 是一个结构体,内部有一个 receiver 实例,和一 个 Class super_class,指向了当前类的父类 Class ,通过这个父类可以直接的从父类里边开始查找方法,由于消息接收者还是当前类的实例对象 self, 最终如果在父类中没有找到class 这个方法,会在 Person 类的父类 NSObject 中去查找 class 方法,由于 NSObject 的 class 方法,调用的是 object_getClass(self) ,所以最终消息接收者为 student 实例对象,所以返回的还是 Student .
``
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
if !defined(__cplusplus) && !OBJC2
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
else
__unsafe_unretained _Nonnull Class super_class;
endif
/* super_class is the first class to search */
};
endif
作者:大兵布莱恩特0409
链接:https://juejin.im/post/5b46e5b1f265da0f6b76ee91
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
``
性能相关
1:异步绘制
https://www.jianshu.com/p/6634dbdf2964
https://www.jianshu.com/p/e2c5b2bab063
1.1 渲染上屏
https://cloud.tencent.com/developer/article/1071034
iOS 上视图或者动画渲染的各个阶段:
在 APP 内部的有4个阶段:
布局:在这个阶段,程序设置 View / Layer 的层级信息,设置 layer 的属性,如 frame,background color 等等。
创建 backing image:在这个阶段程序会创建 layer 的 backing image,无论是通过 setContents 将一个 image 传給 layer,还是通过 [drawRect:] 或 [drawLayer: inContext:] 来画出来的。所以 [drawRect:] 等函数是在这个阶段被调用的。
准备:在这个阶段,Core Animation 框架准备要渲染的 layer 的各种属性数据,以及要做的动画的参数,准备传递給 render server。同时在这个阶段也会解压要渲染的 image。(除了用 imageNamed:方法从 bundle 加载的 image 会立刻解压之外,其他的比如直接从硬盘读入,或者从网络上下载的 image 不会立刻解压,只有在真正要渲染的时候才会解压)。
提交:在这个阶段,Core Animation 打包 layer 的信息以及需要做的动画的参数,通过 IPC(inter-Process Communication)传递給 render server。
2: 大图处理
https://www.jianshu.com/p/fa48e8d5f9e4
首先排除CoreGraphics和Image I/O,UIKit解压后占内存比CoreImage小,但是解压过程中比CoreImage占内存大
//这里在cell 上加载图片的耗时操作没写
/*分析卡顿的原因:
所有的Cell的加载都在主线程的一次Runloop循环中,UI渲染也属于Runloop的事情,但是一次渲染18张图片,渲染太多。导致卡顿
解决思路:一次Runloop循环,只加载一张图片
步骤:
1.观察(observer)Runloop的循环
2.一次Runloop循环,加载一张图片
|-Cell加载图片的方法放到数组里
|-Runloop循环 一次,就从数组取出一个图片加载
*/
- (void)viewDidLoad {
[self addRunloopObserver];
self.tasks = NSMutableArray.array;
[self addTask:^{
}];
}
- (void)addTask:(RunloopBlock)task{
//保存任务到数组
[self.tasks addObject:task];
if (self.tasks.count == 0) {
return;
}
if (self.tasks.count>18) {
[self.tasks removeObjectAtIndex:0];
}
}
- (void)addRunloopObserver{
//获取当前的runloop
CFRunLoopRef runloop = CFRunLoopGetCurrent();
//定义上下文
/*
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopObserverContext;
*/
CFRunLoopObserverContext context = {
0,
(__bridge void *)self,
&CFRetain,
&CFRelease,
NULL
};
//创建观察者
//c 中create new copy 堆区开辟内存空间。需要释放
CFRunLoopObserverRef runLoopObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &callback, &context);
CFRunLoopAddObserver(runloop, runLoopObserver, kCFRunLoopCommonModes);
//释放
CFRelease(runloop);
}
void callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
ViewController *vc = (__bridge ViewController *)info;
if (vc.tasks.count == 0) {
return;
}
RunloopBlock task = vc.tasks.firstObject;
task();
[vc.tasks removeObjectAtIndex:0];
};
3:H5的优化处理
https://cloud.tencent.com/developer/article/1137813
4:启动优化
https://cloud.tencent.com/developer/article/1071732
稳定性相关
1:内存OOM
https://cloud.tencent.com/developer/article/1071837
2:webview白屏
iOS 9以后 WKNavigtionDelegate 新增了一个回调函数:
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
当 WKWebView 总体内存占用过大,页面即将白屏的时候,系统会调用上面的回调函数,我们在该函数里执行[webView reload](这个时候 webView.URL 取值尚不为 nil)解决白屏问题。在一些高内存消耗的页面可能会频繁刷新当前页面,H5侧也要做相应的适配操作。
并不是所有H5页面白屏的时候都会调用上面的回调函数,比如,最近遇到在一个高内存消耗的H5页面上 present 系统相机,拍照完毕后返回原来页面的时候出现白屏现象(拍照过程消耗了大量内存,导致内存紧张,WebContent Process 被系统挂起),但上面的回调函数并没有被调用。在WKWebView白屏的时候,另一种现象是 webView.titile 会被置空, 因此,可以在 viewWillAppear 的时候检测 webView.title 是否为空来 reload 页面。
综合以上两种方法可以解决绝大多数的白屏问题。
系统架构相关
1:秒杀系统的设计
https://segmentfault.com/a/1190000020970562
2:weex架构
https://cloud.tencent.com/developer/article/1071837
面试相关
https://juejin.im/post/5d9f3f4d518825358b221435#heading-53
知识点汇总
https://www.yuque.com/alexiiio/ldnotes/abbvb8
多线程考察
https://juejin.im/post/5d89796a6fb9a06af13da988#heading-13
https://github.com/iteatimeteam/Friday-QA/issues/2
启动治理
https://tech.meituan.com/2018/12/06/waimai-ios-optimizing-startup.html
直播相关
https://cloud.tencent.com/developer/article/1071631
openGL
https://cloud.tencent.com/developer/article/1427622
数据结构
https://juejin.im/post/5c9adba6f265da60fb3bfe60