iOS 使用 lldb 断点加载调试工具如 Reveal-Lookin-Woodpecker
整体的 lldb 加载命令如下, 放在 ~/.lldbinit 文件内 ### Reveal LLDB commands support - DO NOT MODIFY command
每天都要有思考 iOS每日一题 今天是....
ImageBuffer = widthOfImage * heightOfImage * 4; // in pixel not in point
图片显示占用内存大小 = 图片的宽度 乘以 图片的高度 乘以 颜色 RGBA 占用的4个字节;
png
, jpeg
等格式, 这些不能被用来直接显示;bitmap
位图的方式. 要从硬盘中的容器格式变成位图,就会经历 图片解码的过程. 而解码后的位图大小计算方式如上记录于2018/11/11
OOM
imageWithName
initWithContentOfFile
imageWithData
等方式, 当我们调用这些方法时, 系统会自动的将这些从不同途径获取到的图片进行 主线程CPU图片解码 从而让图片正常显示出来.OOM
导致手机闪退.SDWebImage
被用来快速加载网络图片, 其底层会对大部分图片进行显示前的解码操作,而不是等系统自己去解码,从而降低了 CPU
的负荷,让主线程快速响应任务.SDWebImage
有个缺陷是 对于大图的一次性解压操作会使内存暴增,导致闪退.
GPU
分片解码的方式,从而使内存不会出现一次性的暴涨.当然也有人说可以关闭图片的异步解码
[[[SDImageCache sharedImageCache] config] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
当然我不建议这样处理. if you set this to false, the decompression will be done by the UIKit in main thread which will cause a drop in FPS
Image
的视频,记录于 2018/11/11
podfile
中的 use_frameworks
意味着什么,使用与不使用的区别use_frameworks
即使用动态库的方式进行依赖.Cocoapods1.5.0
才官方支持 swift
静态库记录于 2018/11/12
IMP
_cmd
SEL
Method
isa
是什么, 在开发中可以怎么使用?首先官方文档
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
opaque
含义: opaque
直译的意思是不透明的,C
语言中允许通过 typedef
申明一个抽象的结构体类型,你无需定义struct
__opaque
的具体实现,就能在其他函数的声明中使用该数据类型的 _指针_Class
id
IMP
通通都是结构体指针, 也是 Objective-C
是 C
语言超集的原因Class
是 类的结构体 objc_class
的指针id
是 对象的结构体 objc_object
的指针SEL
是 方法选择子结构体 objc_selector
的指针
NSMethodSignature
要结合 class
存在, 不同的类可以由 相同的 SEL
, 但是不能有 相同的方法签名._cmd
, 代表当前方法的 selector
, 也就是Method 中的 IMP 真正关联的 SELIMP
是 方法实现函数 void (*)(void /* id, SEL, ... */ )
的别名, 类似 Block
的感觉
OBJC_OLD_DISPATCH_PROTOTYPES
是一个编译选项, 我们可以在 Xcode
设置 YES or NO
这样 IMP
就会有不同的解释, 如果是 YES
那么 我们使用 IMP
时就要注意两个 不为空的参数问题IMP
肯定要比完全走一遍 runtime
要快得多, 不过也少了 runtime
很多的黑科技另附上摘抄自method-swizzling的
Selector
(typedef struct objc_selector *SEL):在运行时 Selectors 用来代表一个方法的名字。Selector 是一个在运行时被注册(或映射)的C类型字符串。Selector由编译器产生并且在当类被加载进内存时由运行时自动进行名字和实现的映射。Method
(typedef struct objc_method *Method):方法是一个不透明的用来代表一个方法的定义的类型。Implementation
(typedef id (*IMP)(id, SEL,...)):这个数据类型指向一个 方法的实现的最开始的地方。该方法为当前CPU架构使用标准的C方法调用来实现。该方法的第一个参数指向调用方法的自身(即内存中类的实例对象,若是调用类方法,该指针则是指向元类对象 metaclass )。第二个参数是这个方法的名字 selector,该方法的真正参数紧随其后。那么后面看看 isa
的秘密吧 ,这里会涉及到 类与对象的关系
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // isa 指针
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE; //父类的指针
const char * _Nonnull name OBJC2_UNAVAILABLE; //类名
long version OBJC2_UNAVAILABLE; // 版本号
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE; //实例变量的大小, 所有的实例变量
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; // 实例变量的链表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; // 方法的链表, 分类的实现逻辑即动态向其中添加方法
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; // 方法缓存的链表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; // 协议的链表
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
按照顺序来看, 显示一个对象的结构体 objc_object
中有一个 isa
, 它是 类的结构体 objc_class
的指针 Class
(指向一个类), 而类的结构体 objc_class
中也有 isa
, 这样就形成了一个链式结构,那它指向哪儿呢. 再看
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
... 省略
}
而从上面可以看到, objc_class
继承自 objc_object
, 意味着它也是一个对象;
那么既然 类也是一个对象 (类对象), 那么它是谁的实例呢?
实际上它是元类 (metaClass
) 的对象, 见下图!
上图可以清晰的描述出对象与类的关系. 而联系他们的就是 isa
了!!!
isa
指向 类 (即类对象)isa
指向其 metaClass
元类isa
指向其 根元类, 根元类指向自身superclass
superclass
就是其类对象的 superclass
superclass
指向 👆 父级 (也是一个类对象), 依次向上一直到 NSObject
, 然后是nilisa
表示的是一个 归属superclass
表示的是 继承关系isa
和 superclass
指向不同isa
它是一个指向对象的类定义的指针. 也是这个对象内存地址的首地址.
A pointer to the class definition of which this object is an instance , Every Objective-C object hides a data structure whose first member—or instance variable—is the isa pointer. The isa pointer is critical to the message-dispatch mechanism and to the dynamism of Cocoa objects.
Class isa;
这里还要补充的是, 除了上图中的 isa
连线, 我们还要知道 isa
如何起作用.
普通意义上的对象 在调用 实例方法的时候, 是要通过其 isa
指针查找到其 类对象 (内存区域在__代码段__),然后找到 class_data_bits_t
,也就是类对象的数据区 class_data_bits_t is the class_t->data field (class_rw_t pointer plus flags)
, 从这里查找相应方法的实现, 注意是IMP
所指向的函数内存首地址. (具体的查找细节就不说了, 关键词是如上图 上溯)
而普通意义上的对象 在调用 类方法的时候, 和上面一条类似, 类对象自身的内存区域也不会存储的, 它会查找 isa
指向的 元类, 从中取查找 方法的实现, 如果是继承的方法,那么它会继续向它元类的父级查找,一直找到定义它的地方!
cache
缓存链表,再 methodLists
, 再 super
...main
方法之前会被实例化 iOS 程序 main 函数之前发生了什么对象在堆区, 只有实例变量, 不保存对象方法列表
类对象在全局变量, 保存对象方法(也就是对象实例的元数据), 不保存 类方法列表
元类在全局变量, 保存类方法列表, 继承链中的每一个类 都有一个元类 (因为需要保存自己独有的类方法)
记录于 2018/11/13
setter
才可以if-else
, 而采用策略模式记录于 2018/11/14
目录
Wikipedia中对信号量 的描述如下:
信号量(英语:Semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。
当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。
当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。
semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态.
semaphore对象适用于控制一个仅支持有限个用户的共享资源,是一种不需要使用忙碌等待(busy waiting)的方法。
归纳几点:
① 信号量 wait 等待操作, 将同步对象的值 原子-1
CPU
资源较少.② 信号量 release 操作, 值 原子+1
. 这个动作是在离开临界区时执行的, 此时如果有被挡住的线程,那么就可以去获取这个锁, 进入临界区.
如果信号量是一个任意的整数,通常被称为计数信号量(Counting semaphore)
,或一般信号量(general semaphore)
;如果信号量只有二进制的0或1,称为二进制信号量(binary semaphore)
。在 linux
系统中,二进制信号量(binary semaphore)
又称互斥锁(Mutex)
.
iOS 中的信号量也是基于 锁机制
- 线程加锁 (计数器设置为 **1**)
- 线程同步 (计数器设置为 **1**)
- GCD 中 线程最大并发控制 (计数器设置为 **N**) , 推荐使用 `NSOperationQueue`
- 实现类似 `GCD Group` 任务依赖的功能
记录于 2018/11/15
UICollectionView
自定义布局的性能优化方式 ?记录于 2018年11月16日
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中
记录于 2018年11月17日
天天一问 by manajay