知识点

280 阅读5分钟

Runtime场景:

  • 发送消息objc_msgSend
  • 交换方法
  • 动态添加方法
  • 动态添加属性,属性关联
  • 字典转模型

RunLoop使用场景 :

  • 一、保证线程长时间存活
  • 二、RunLoop如何保证NSTimer在视图滑动时依然能正常运转
  • 三、RunLoop如何保证不影响UI卡顿
  • 四、使用RunLoop 监测主线程卡顿,在主线程的RunLoop中添加一个observer,检测从 kCFRunLoopBeforeSources 到 kCFRunLoopBeforeWaiting 花费的时间是否过长。
  • 五、监听kCFRunLoopBeforeWaiting,在RunLoop空闲时间内处理任务,比如下载图片

自动释放池

@autoreleasepool是一个由AutoreleasePoolPage组成的双向链表,在RunLoop启动时创建,在当前迭代停止时释放当前释放池内的对象。

首先执行objc_autoreleasePoolPush,向当前自动释放池插入一个哨兵对象,再将管理对象压入;如果自动释放池已满则新生成AutoreleasePoolPage并接在旧的后面。

释放时根据传入的哨兵对象地址找到哨兵对象所处的page,在当前page中,将晚于哨兵对象插入的所有autorelease对象都发送一次- release消息,并向回移动next指针到正确位置。

主动释放,执行drain。

路由设计:

  • 1、采用OpenURL方式(另外有Universal Links方式)
  • 2、下发配置,启动时候注册
  • 3、远程调用:解析URI,获取target,执行action
  • 4、本地调用:获取target,执行action(performSelector的方式)
  • 5、路由声明Protocol,服务方遵循后实现相关方法
  • 6、默认全局以及自定义的容错处理方式

+load和+initialize:

说明 +load +initialize
调用时机 被添加到 runtime 时 收到第一条消息前,可能永远不调用
调用顺序 父类load->子类load,主类load->分类load;不同分类之间的+load方法的调用顺序跟编译顺序有关 按消息传递机制:子类的分类->子类->父类的分类->父类 查找,找到则停止
调用次数 各自自身方法各调用1次 跟具体实现有关,如果子类与分类都未实现,那么父类的会调用多次
是否需要显式调用父类实现
是否沿用父类的实现 是(父子类都实现时需要区分不同实现)
分类中的实现 类和分类都执行 覆盖类中的方法,只执行分类的实现
使用 一般用来实现 Method Swizzle 一般用来初始化全局变量或者静态变量
实现 直接使用函数内存地址的方式 (*load_method)(cls, SEL_load)执行 使用发送消息 objc_msgSend 的方式

锁:

atomic 使用了原子性,能保证线程安全,其中用了自旋锁spinlock_t

1	NSLock                 互斥锁
2	NSRecursiveLock 递归锁
3	NSCondition         特殊锁(线程直接的调度,两个线程直接下载图片与图片处理)
4	NSConditionLock  互斥锁与条件锁的组合,处理两个线程按特定顺序执行
5	pthread_mutex      互斥锁
6	pthread_rwlock     读写锁
7	POSIX Conditions 条件锁需要互斥锁和条件两项来实现
8	OSSpinLock          自旋锁(有优先级反转问题)
9	os_unfair_lock        OSSpinLock等替代品(iOS10之后支持)
10	dispatch_semaphore 信号量
11	@synchronized      便捷的创建互斥锁的方式

NSLock < NSCondition < NSRecursiveLock < NSConditionLock 
OSSPinLock < os_unfair_lock < gcd < pthread < NSLock < @synchronized

iOS 成员变量,实例变量,属性变量的区别:

成员变量是定义在{}号中的变量,如果变量的数据类型是一个类则称这个变量为实例变量。因为实例变量是成员变量的一种特殊情况,所以实例变量也是类内部使用的,无需与外部接触的变量,这个也就是所谓的类私有变量。而属性变量是用于与其他对象交互的变量。

  1. nonatomic<-->atomic(默认)
  2. readwrite<-->readonly(默认)
  3. retain/copy/assign

iOS等宽字体:

[UIFont fontWithName:@"HelveticaNeue" size:16];

内存区

  1. 栈区 内存管理由系统控制,存储的为非静态的局部变量,例如:函数参数,在函数中生命的对象的指针等。当系统的栈区大小不够分配时, 系统会提示栈溢出。

  2. 堆区 内存管理由程序控制,存储的为malloc , new ,alloc出来的对象。 如果程序没有控制释放,那么在程序结束时,由系统释放。但在程序运行过程中,会出现内存泄露、内存溢出问题。 分配方式类似于链表。

  3. 全局存储区(静态存储区) 全局变量、静态变量会存储在此区域。事实上全局变量也是静态的,因此,也叫全局静态存储区。 存储方式: 初始化的全局变量跟静态变量放在一片区域,未初始化的全局变量与静态变量放在相邻的另一片区域。 程序结束后由系统释放。

  4. 文字常量区 在程序中使用的常量存储在此区域。程序结束后,由系统释放。在程序中使用的常量,都会到文字常量区获取。

  5. 程序代码区 存放函数体的二进制代码。 运行程序就是执行代码,代码要执行就要加载进内存。

各种回调的同步异步

NSNotification、KVO、Delegate在哪个线程中触发,就在哪个线程中响应,而且都是同步的,会阻塞当前线程,直到处理完成。