1、修饰属性有哪几个?追问 为什么用copy?weak对象为nil的底层原理?
2、block是什么?block有几种?追问 为什么__block修饰的值在内部可以改变
3、字典大致实现原理
4、一般开始做一个项目,你的架构是如何思考的?
5、runLoop机制?source0是什么?source1是什么?追问 事件响应时怎么通知runLoop的?
6、runtime是什么?superclass是什么类型的?math_list里有什么?追问SEL里面有什么(知道的请告诉我,查资料没找到)?
7、objc_class结构体
一、类在OC中是objc_class的结构体指针 typedef struct objc_class *Class;
在objc/runtime.h中objc_class结构体的定义如下:
Class isa OBJC_ISA_AVAILABILITY;
#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; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
isa: 指向元类的objc_class结构体指针,iOS中的类也是对象,元类中储存有类对象的类方法;
superclass: 指向父类的objc_class结构体指针,可以通过父类的指针找到变量和方法;
name: 类名;
version: 版本号,默认为0
info: 其他信息,运行期间的一些位标示
instance_size:类实例变量大小
objc_class的定义
我们在使用runtime以class为前缀的方法时主要就是针对这个结构体中的各个字段的。
指向元类的指针(isa)
在OC中所有的类其实也是一个对象,那么这个对象也会有一个所属的类,这个类就是元类也就是结构体里面isa指针所指的类。
7、那什么是元类呢?
元类的定义:元类就是类对象的类。每个类都有自己的元类,因为每个类都有自己独一无二的方法。
简单点说就是:
当你给对象发送消息时,消息是在寻找这个对象的类的方法列表。(实例方法)
当你给类发消息时,消息是在寻找这个类的元类的方法列表。(类方法)
那元类的类是什么呢?
元类,就像之前的类一样,它也是一个对象。你也可以调用它的方法。自然的,这就意味着他必须也有一个类。
所有的元类都使用根元类(继承体系中处于顶端的类的元类)作为他们的类。这就意味着所有NSObject的子类(大多数类)的元类都会以NSObject的元类作为他们的类
根据这个规则,所有的元类使用根元类作为他们的类,根元类的元类则就是它自己。也就是说基类的元类的isa指针指向他自己。
这里有一副图可以很好的展现这些关系:
8、category是啥?category为什么不能添加属性?有办法解决吗?
//Category表示一个结构体指针的类型
typedef struct objc_category *Category;
struct objc_category {
char * _Nonnull category_name OBJC2_UNAVAILABLE;
char * _Nonnull class_name OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
分类特点
1.分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性 ;
2.分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量,会编译通过,但是引用变量会报错;
3.如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法,同名方法调用的优先级为 分类 > 本类 > 父类;
可以通过关联对象给Category添加属性
@interface NSObject (Extension)
@property (nonatomic,copy ) NSString *name;
@end
@implementation NSObject (Extension)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self,@selector(name));
}
@end
上面是把我们看到的现象进行分析,思考其为什么会有这样的现象呢?分类并不会改变原有类的内存分布的情况,它是在运行期间决定的,此时内存的分布已经确定,若此时再添加实例会改变内存的分布情况,这对编译性语言是灾难,是不允许的。
9、如果一个类有两个相同的分类,系统会调用哪个分类的方法?
10、KVO怎么实现,_会不会触发,成员变量会不会触发,kvc+成员变量会不会触发,不用setter怎么触发kvo
答. 当一个对象使用了KVO监听,iOS系统会修改这个对象的isa指针,
改为指向一个全新的通过Runtime动态创建的子类,子类拥有自己的set方法实现,
set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、
didChangeValueForKey方法,而didChangeValueForKey方法内部
又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法。
如何手动触发KVO
答. 被监听的属性的值被修改时,就会自动触发KVO。
如果想要手动触发KVO,则需要我们自己调用willChangeValueForKey和
didChangeValueForKey方法即可在不改变属性值的情况下手动触发KVO
,并且这两个方法缺一不可。
11、iOS反射机制?
12、iOS的timer和CADisplay的区别?
13、用过 TableView 吗,平时怎么解决 TableView 滑动卡顿问题的?
14、谈谈对多线程的使用和理解?
15、项目中遇到过abort()吗?如何定位和解决abort()?
备用:
iOS有哪几种锁?比较各种锁的优缺点?并给出实例场景判断用哪种锁