事件传递 & 事件响应
Last-Modified:服务器会在资源后面有个标记Last-Modified,表示最后修改时间。第一次请求会缓存这个时间,后面请求时候,发送一个If-Modified-Since报头。如果返回304就不会传输资源数据,用本地缓存的即可。否则会传输资源。Etag:服务器对资源实体用Etag来标记,就是对实体进行散列计算,得到唯一值。第二次请求,对这个值进行比较。如果返回304就数据为空,和上述情况一样。.o 或 .a 文件(目标文件).dylib 或 .framework (动态库文件)dyld的路径dyld 加载到内存中dyld 递归加载所有的动态连接库dylibldid -e 命令导出可执行文件的签名文件entitlementsSpringBoard的签名文件entitlementsSpringBoard的签名文件覆盖自己的APP的签名文件entitlements属性成员信息、方法信息复用消息传递,在OC的消息传递过程中,只要是这个群体的实体,就不需要关心自身的类型是什么,只需要关心这个接口。在传递消息的时候就可以复用了。复用消息传递机制,所以也就产生了针对类的元类,本质上来说,我认为也是消息传递的复用工具[self.person addObserver:self forKeyPath:@"age" options:options context:nil]; NSKVONotifying_Person 继承 Person 类willChange和didChange方法methodForSelector方法,查看实际上调用的方法是什么class_copyMethodList方法,也可以获取添加监听后的类的所有的方法列表,打印就会发现与添加之前不一样了。object_getClass获取类名,打印也会发现与添加之前不一样willChange和didChange方法不会调用set方法,不会触发KVO[self.person setValue:@10 forKey:@"age"];[self.person setValue:@20 forKeyPath:@"cat.weight"];分类的使用场景:一般业务比较复杂,需要将一部分功能或业务逻辑分模块出来,就可以用分类
Category的本质
objc_setAssociatedObjectobjc_getAssociatedObjectCategory和Extension的区别(OC里)
Class currentClass = [TestClass class];
TestClass *my = [[TestClass alloc] init];
if (currentClass) {
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
IMP lastImp = NULL;
SEL lastSel = NULL;
for (NSInteger i = 0; i < methodCount; i++) {
Method method = methodList[i];
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))
encoding:NSUTF8StringEncoding];
if ([@"printName" isEqualToString:methodName]) {
lastImp = method_getImplementation(method);
lastSel = method_getName(method);
}
}
typedef void (*fn)(id,SEL);
if (lastImp != NULL) {
fn f = (fn)lastImp;
f(my, lastSel);
}
free(methodList);
}
在oc中打开objc.h
typedef struct objc_class *Class; //Class是指向结构体objc_class的指针
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; //方法缓存列表(是个hash表),用来消息发送时候,快速查找方法
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; //类实现协议列表
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
// JHPerson 和 JHTeacher 都是 Person 的子类,并且只有Person这个父类实现了+initialize方法
- (void)testInit {
NSLog(@"--------");
[JHPerson alloc];
[JHPerson alloc];
[JHTeacher alloc];
[JHTeacher alloc];
}
// 伪代码逻辑
if (JHPerson没有初始化) {
if (JHPerson的父类Person没有初始化) {
objc_msgSend([Person class], @selector(initialize)); // 第一次调用父类
}
objc_msgSend([JHPerson class],@selector(initialize)); // 调用子类,子类没实现,去找到父类调用,第二次调用父类
}
if (JHTeacher没有初始化) {
if (JHTeacher的父类Person没有初始化) { // 父类已经初始化了,不会进来
objc_msgSend([Person class], @selector(initialize));
}
objc_msgSend([JHTeacher class],@selector(initialize)); // 调用子类,子类没实现,去找到父类调用,第三次调用父类
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PeWg5rcG-1659199501480)(:/30c14379e1d04de58fd6b16fbc2fb6dd)]](https://1000bd.com/contentImg/2022/08/03/034951887.png)
struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding; // 这个指针指向自己
int __flags;
int __size;
int age;
};
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dm6wIdsq-1659199501482)(:/0f99685a42514e41ad6c3e4a2797c715)]](https://1000bd.com/contentImg/2022/08/03/034952028.png)
过河拆桥法,方便记忆。强指针指向实例对象,__block对实例对象产生了强引用实例对象调用block对象,实例对象对block产生了强引用block再访问了__block对象的内容,block对__block产生了强引用,如图:// 1. __block修饰的那部分:__block Person *person = [[Person alloc] init];
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
Person *__strong person; // 后面使用的person指针,都是这个指针
};
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iVMOYnk5-1659199501506)(:/1a2c46f22eaf41ba96794a004f9651d9)]](https://1000bd.com/contentImg/2022/08/03/034952156.png)
- 5. 现在我要过河拆桥,我调用block的时候,通过__block访问到了我想要访问的实例对象的属性(比如,这里我的目的就是访问person.age),那么我的目的已经完成了,所以,我不再需要让__block对象再去强引用实例对象了。
// 1. __block修饰的那部分:__block Person *person = [[Person alloc] init];
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
Person *__strong person = nil; // 在这里来过河拆桥,把它变为nil
};

@synchronized(obj) {
// do work
}
转化成这样的东东:
@try {
objc_sync_enter(obj);
// do work
} @finally {
objc_sync_exit(obj);
}
// Begin synchronizing on 'obj'.
// Allocates recursive mutex associated with 'obj' if needed.
// Returns OBJC_SYNC_SUCCESS once lock is acquired.
// 开始在obj上执行同步操作, 懒加载生成一个递归锁关联obj, 返回OBJC_SYNC_SUCCESS
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
// 查找这个obj是否已经生成SyncData,如果没有生成一个
SyncData* data = id2data(obj, ACQUIRE);
assert(data);
data->mutex.lock(); // 调用SyncData的递归锁加锁
} else {
// @synchronized(nil) does nothing
// 如果传入nil, 打印了一个log,然后什么都不做
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
return result;
}
// End synchronizing on 'obj'.
// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
// 结束在obj上的同步操作,
int objc_sync_exit(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
//还是找到这个对象所在的结构体SyncData
SyncData* data = id2data(obj, RELEASE);
if (!data) {
// 如果这个结构体在block执行过程中找不到了,会返回error
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
} else {
// 尝试解锁,解锁失败也会返回error
bool okay = data->mutex.tryUnlock();
if (!okay) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
}
}
} else {
// @synchronized(nil) does nothing
// 如果这个对象在block执行过程中变成nil了,会什么都不做
}
return result;
}
data->mutex.lock(); // 调用SyncData的递归锁加锁 怎么调?typedef struct SyncData {
id object;
recursive_mutex_t mutex;
struct SyncData* nextData;
int threadCount;
} SyncData;
typedef struct SyncList {
SyncData *data;
spinlock_t lock;
} SyncList;
// Use multiple parallel lists to decrease contention among unrelated objects.
#define COUNT 16
#define HASH(obj) ((((uintptr_t)(obj)) >> 5) & (COUNT - 1))
#define LOCK_FOR_OBJ(obj) sDataLists[HASH(obj)].lock
#define LIST_FOR_OBJ(obj) sDataLists[HASH(obj)].data
static SyncList sDataLists[COUNT];
----------
SyncData中的recursive_mutex_t最终是recursive_mutex_tt类型,
recursive_mutex_tt内部有个pthread_mutex_t的锁,
这个锁初始化为一个递归锁 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
----------
class recursive_mutex_tt : nocopy_t {
pthread_mutex_t mLock;
public:
recursive_mutex_tt() : mLock(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) {
lockdebug_remember_recursive_mutex(this);
}
recursive_mutex_tt(const fork_unsafe_lock_t unsafe)
: mLock(PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
{ }
void lock()
{
lockdebug_recursive_mutex_lock(this);
int err = pthread_mutex_lock(&mLock);
if (err) _objc_fatal("pthread_mutex_lock failed (%d)", err);
}
void unlock()
{
lockdebug_recursive_mutex_unlock(this);
int err = pthread_mutex_unlock(&mLock);
if (err) _objc_fatal("pthread_mutex_unlock failed (%d)", err);
}
..... 其他方法
};
Witness Table ,类会有一个数组存储里面的函数指针。