1.weak 和 assign 不同
1.weak 和 assign 不同
weak
必须用于oc
对象assign
可以用于非oc
对象weak
可以用来解决循环引用问题weak
修饰的属性表示一种非持有关系 给该对象设置新值时 设置方法既不保留新值也不释放旧值 在属性遭到摧毁时会自动制空weak
可以用来修饰已经被强引用过得对象 比如使用xib
进行布局时设置的属性
2.weak 的实现原理
runtime
维护了一个全局的weak
引用表weak_table_t
(封装版本为SideTable
) 其底层是一个hash
表(一种key value
存储的数据结构 在cpp
中体现为struct
) 用于存储weak
引用对象key
是所指对象地址value
是weak
指针地址weak
对象释放自动置空实现: 在对象释放的最后一步objc_clear_deallocating
根据对象地址获取所有weak
指针的数组 遍历这个数组把其中的额数据置为空oc
对象释放的顺序:objc_release
,dealloc
大部分对象是在这一环节被销毁的 其中主要做的事情为 object_dispose() associate 绑定的对象也是在这里销毁 所以不管是MRC还是ARC都不需要在dealloc
中再次释放 associate 绑定对象,_objc_rootDealloc
,objc_destructInstance
,objc_clear_deallocating
3.copy修饰的属性
copy
即对象的浅拷贝copy
修饰的属性的值会有被保护
的作用 一般copy
会用来修饰不可变对象 比如NSString, NSArray
等 这样的对象在被可变对象接收以后 其值仍然不可变 可以利用此封装性质封装一些数据- 自己的属性想实现
copy
需要实现NSCopying
协议 并实现- (id)copyWithZone:(NSZone *)zone
方法
4.@property的本质
- 属性的本质是
getter
+setter
+ivar
- 属性自动合成(autosynthesis)的规则: 自动合成会生成下面五个东西
// 该属性的偏移量 这个偏移量是硬编码 标示该变量距离存放对象的内存地址有多远 OBJC_IVAR_$类名$属性名 getter与setter方法对应的实现函数 // 成员列表 ivar_list // 方法列表 method_list // 属性列表 prop_list
每增加一个属性 系统都会在
ivar_list
中添加一个成员变量的描述 在method_list
中增加getter
与setter
方法的描述 在prop_list
中给出属性描述 然后计算属性在对象中的偏移量然后根据偏移量的位置 实现具体的setter
方法与getter
方法
5. @synthesize 和 @dynamic
@sythesize
如果没有手动实现getter
和setter
由编译器自动创建 默认为@syntheszie var = _var;
@dynamic
getter
和setter
都需要手动创建
6.ARC下 不指定属性任何的关键字 默认的修饰符有哪些
atomic
readwrite
string
oc 对象atomic
readwrite
assign
基本类型
7.objc_msgSend()
Objective-C
是动态语言 每个方法会在运行时被动态转为消息发送 即objc_msgSend(receiver, selector)
oc
类的基本结构:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,runtime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在method Lists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
unrecognized selector
就是由于消息转发的时候没有在方法列表中找到产生的
消息转发过程
objc_msgForward
:
- objc在向一个对象发送消息时
runtime
会根据对象的isa
指针找到该对象所属的类 然后在该类的方法列表中查找目标方法 如果该类中没有这个方法 则去父类中查找 一直查找到父类的最上层- 如果父类的最上层也没有找到相对应的方法 则会报
unrecognized selector
但在这之前 仍有三次补救的机会- 第一次补救机会
Method resolution
:runtime
会调用本类中+resolveInstanceMethod:
或+resolveClassMethod:
让你提供一个函数实现 如果你添加了目标函数 那runtime
会重新启动一次消息发送的过程 否则则运行到下一步 消息转发- 第二次补救机会
Fast forwarding
: 如果目标对象实现了-forwardingTargetForSelector:
runtime
就会调用这个方法 根据这个方法返回的对象(不为nil或self)重启消息发送, 当然新的消息放松过程也会转移到返回的对象上面 否则则进行最后一次消息转发- 第三次补救机会
Normal forwarding
: 首先runtime
会发送-methodSignatureForSelector:
获得函数的参数及返回类型 如果-methodSignatureForSelector:
返回了nil
这时程序就会崩溃 如果返回了一个函数签名 则runtime
会生成一个NSInvocation
对象并发送-forwardInvocation:
给目标对象 (有些框架 例如JSPatch
需要利用第三步返回的NSInvocation
自定义实现 而直接调用了objc_msgForward
这样原来的方法就不会被执行 而是走了别的实现)
8.下面的代码输出什么
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class])); // Son
NSLog(@"%@", NSStringFromClass([super class])); // Son
}
return self;
}
@end
都是
Son
super
和self
指向同一个消息接收者super
会在父类中调用而已 但他仍然是本类对象
9.objc 中类方法和实例方法有什么本质区别和联系
类方法:
- 类方法是属于类对象的
- 类方法只能由类对象调用
- 类方法中的self是类对象
- 类方法可以调用其他类的方法
- 类方法中不能访问成员变量
- 类方法中不能直接调用对象方法
实例方法:
- 实例方法是属于实例对象的
- 实例方法由对象实例调用
- 实例方法中的self是实例对象
- 实例方法中可以访问成员变量
- 实例方法中可以调用实例方法
- 实例方法也可以调用类方法(通过类名)
10.能否想编译后的类中添加实例变量 运行时呢?
不能向编译后的类中添加实例变量 运行时可以 因为编译后的类已经在
runtime
中注册类结构体中的实例变量链表objc_Ivar_list
和实例变量内存instance_size
大小已确定
运行时可以添加但的在类被创建但还没有向
runtime
注册之前objc_allocateClassPair
-objc_registerClassPair
区间内