这次面试问了很多问题,但其实有很多都是自己学过或者了解过的,但是没有及时复习,导致很多知识遗忘了,这次最大的经验教训就是不管是什么点,都要反复反复的去看,温故而知新!不着手 = 不复习 = 遗忘 = 掌握情况下降,还有就是计算机基础有些也没有去再多看多学,例如数据库的很多东西自己概念也不清晰了
但是这次面试让我发现了自己很多的问题!虽然存在应该把握却没有把握好的地方,可塞翁失马焉知非福,找到自己的漏洞和缺陷可以更好的进步!
对于还没有学习的点例如网络编程、项目开发等,可以在后续的学习中继续填补
Runtime
其实消息调用和转发就是要找到响应者和对应的方法实现,消息的调用过程就是在类中找,如果没有找到就到消息转发阶段
消息转发的步骤就是(通俗的说):
先自己动态添加方法(找不到方法我就自己添加一个方法实现) --> 将消息发送给其他对象(我转发给其他人看看别人能不能实现) --> 最后一次消息分发了,可以发给很多不同的对象或者直接自己“消化” --> 真的没有办法了,我只能报错了
问题:消息重定向这里没有描述清楚 (其实自己当时学的时候就不太清楚这里到底是什么目的)
记得关键字:函数签名 --> -methodSignatureForSelector
- 利用
-methodSignatureForSelector
获取函数签名(函数的参数和返回值类型),系统会创建一个NSInvocation对象
,并通过forwardInvocation:
消息通知该对象,给予此次消息发送最后一次寻找IMP的机会 - 如果
-methodSignatureForSelector
返回了一个nil(没有获取函数签名),系统发出-doesNotRecognizeSelector:
消息,程序崩溃
// 获取函数的参数和返回值类型,返回签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
// 消息重定向
- (void)forwardInvocation:(NSInvocation *)anInvocation;
对于 forwardInvocation:
,我们可以在该方法中对不能处理的消息做一些处理,也可以将消息转发给其他对象处理,而不抛出错误
这个方法只有一个参数 NSInvocation对象
,该对象其实就是我们说的函数签名,里面封装了函数的参数和返回类型
那么我们的 NSInvocation对象
是从哪里哪里来的呢?
其实就是在调用 forwardInvocation:
方法之前,Runtime系统调用 -methodSignatureForSelector
,取得返回的函数签名用于生成
NSInvocation对象
所以我们重写 forwardInvocation:
方法的同时也需要重写
-methodSignatureForSelector
方法,否则会抛出异常
其实 forwardInvocation:
就是一个不能识别消息的分发中心,将这些不能识别的消息转发给不同的消息对象,或者转发给同一个对象,又或者是简单的“吃掉”某些消息,因此没有响应也不会报错,例如我们可以为了避免直接闪退,可以当消息没发处理的时候在这个方法中给用户一个提示,也不失为一种友好的体验
Runloop
其实自己之前也整理过了,但是你不复习就是会遗忘的很快!
发现用思维导图的方式很不错
自己再看看梳理一下自己的点吧
修饰符默认情况
属性默认修饰符:
- 原子性:atomic
- 内存管理:ARC默认是strong
- 读写性: readwrite
基本数据类型默认修饰符:
- 原子性:atomic
- 内存管理:assign
- 读写性:readwrite
copy和strong使用情景
-
strong
- 对应的是weak,weak一般用于防止强引用导致的循环引用
-
copy
-
对于NSString, NSArray, NSDictionary类型(不可变)的属性,它们有对应的可变子类NSMutableString, NSMutableArray, NSMutableDictionary这些子类对象也可以用来给属性赋值
-
就以NSString为例,传递给setter方法的新字符串可能是一个NSMutableString类的实例,这是内容可变的字符串,如果不在setter方法中拷贝一个副本,那么设置完属性后,这个可变字符串可能会在某些时候被无意间进行修改,导致出错
copy经常用于对象的修改、移动和保护。如果上述的几种应用都不需要,持有原始对象的引用就足够了,并不需要copy
-
举个例子
@interface ViewController ()
@property(nonatomic,copy)NSMutableString *mutableString; //copy修饰的可变字符串
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *str = [NSMutableString stringWithFormat:@"1234"]; //可变字符串1234
self.mutableString = str; //将str赋给mutableString
NSLog(@"string:%@ --- mutableString:%@",str,self.mutableString);
[self.mutableString appendString:@"5678"];
NSLog(@"string:%@ --- mutableString:%@",str,self.mutableString);
}
@end
string:1234 --- mutableString:1234
报错原因
unrecognized selector sent to instance
在这里其实出错的关键点在于 self.mutableString = str;
和[self.mutableString appendString:@"5678"];
self.mutableString = str;
这行代码其实就是[self.mutableString setMutableString:str];
,具体实现如下
-(void)setMutableString:(NSMutableString *)mutableString{
if (_mutableString != mutableString) {
[_mutableString release];
_mutableString = [mutableString copy];
}
}
主要的代码_mutableString = [mutableString copy];
- 其中的
mutableString
是传入进来的参数str
- 使用
copy
方法是因为属性由copy
修饰 - 因为
str
本身是可变字符串,因此可变字符串copy
得到的值是不可变对象,即[mutableString copy]
得到的是不可变对象 mutableString
本身虽然一开始定义的是可变字符串,但是不可变对象赋值给了_mutableString
,因此其也还是一个不可变字符串了
而下面又对如今不可变字符串mutableString
进行了[self.mutableString appendString:@"5678"];
- 不可变对象是没有
appendString
方法的,所以报错unrecognized selector sent to instance