前两天的直播: 孙源的面试小灶直播- 简历、面试题、进阶,今天回看,特此笔记下。
- 孙源Sunny 的博客
话说那个经典的 招聘一个靠谱的 iOS 的面试题 就是孙源出的。
直播中的要点:
- 1、面试中的一些问题
- 2、印象比较深的两个题,特别是第二个
- 3、iOS进阶的话题
1、面试中的一些问题
- 注意最近一个工作经历(最重视,尽量详细)
- 细节问题:
大小写、空格之类的,说明的就是标准式,可用 MarkDown - 可以提供更多的信息来体现你的特别
github、blog 的展示 - 专业技能: 到底用这个做过什么?(例如 runtime 具体做过什么,Category 添加属性?替换方法?)
- 项目经验: 也是尽量详细, 可多描述下,自己所处团队中的位置,自己做了一些什么 模块。
另外面试中, 要注意沟通的流畅性,不知道的也可以试探性回答,甚至请教;不要老久不说话,也不要装 X,更不要造假 。
2、印象比较深的两个题,特别是第二个
2-1、 array0 为什么有问题?
- array0 也是有问题的,当外面传入一个NSMutableArray的时候,会产生一些不必要的麻烦
- array1 和 array2 是正常的
- array3 是有问题的,copy 后会让 array3 从NSMutableArray 变成 NSArray ,后期假如使用 插入、删除之类的方法时,就会出现 Crash 的。
此处我的疑惑是 array0 ,因为我一般就是这样写的,虽说传 NSMutableArray 的时候,我一般会 mutableArray.copy 的,但是偶尔也有没传的时候,但是没有出问题啊? 这个一下子没有想到例子...
后来再次看那经典的面试题: 【招聘一个靠谱的 iOS 参考答案(上)】才重新理解了(它里面那个例子错了,可能手误)。
NSArray *array = @[@1, @2, @3, @4];
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
self.array0 = mutableArray;
[mutableArray removeAllObjects];;
NSLog(@"array0 == %@",self.array0);
array0
打印出来就是空的,像上面中当我们使用是strong
,那么这个array0
就指向一个可变对象, 如果这个可变对象在外部被修改了,那么会影响该属性。
父类指针可以指向子类对象,使用copy
的目的是为了让本对象的属性不受外界影响,使用copy
无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
2-2、 Block 的瞬间执行
例如为什么 在下面的方法中,self 不需要写 __weak
和__strong
?
[UIView animateWithDuration:1.0f animations:^{
self.view.alpha = 0.5f;
}];
因为它是瞬间执行的,这个 UIView animationPush 之后,马上就执行了,所以这个 Block 里面不会持有这个 self,所以就不会造成循环引用啦,所以就不需要写啦。
对于这个问题,Sunny 给出了七种方法...
- 1、借助他人, 传入Block ,立即执行掉
- (void)blcokProblemAnswerOne:(void(^)(void))block {
// 让他人帮我们调用
// 立即调用
[UIView animateWithDuration:0 animations:block];
// Or GCD
dispatch_async(dispatch_get_main_queue(), block);
}
- 2、 也是借助他人,传入Block ,手动让其销毁
- (void)blcokProblemAnswerTwo:(void(^)(void))block {
[[NSBlockOperation blockOperationWithBlock:block] start];
}
- 3、NSInvocation 这个类动态实行方法
- (void)blcokProblemAnswerThree:(void(^)(void))block {
[[NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"v@?"]]invokeWithTarget:block];
// v@? 需要详细了解下
}
顺便看看 动态组一个 OC 方法的调用
- (void)testUserInvacation {
NSMethodSignature *singnature = [self methodSignatureForSelector:@selector(description)];
NSInvocation *invacation = [NSInvocation invocationWithMethodSignature:singnature];
invacation.target = self;
invacation.selector = @selector(description);
[invacation invoke];
}
- 4、内部 NSBlock 的方法,这是隐式的API
// 此处推荐了 一个工具 DLIntrospection
- (void)blcokProblemAnswerFour:(void(^)(void))block {
[block invoke];
}
- 5、 通过Blcok 内存的结构来处理
// 需要对指针、地址很熟悉
- (void)blcokProblemAnswerFive:(void(^)(void))block {
/**
struct Block_layout {
void *isa; // 指针
int flags; // 什么类型 (int32_t)
int reserved; // int32_t
void (*invoke)(void *, ...); // C 函数的指针,真正的调用
struct Block_descriptor *descriptor;
// Imported variables.
};
*/
// 目的是找到 void (*invoke)(void *, ...) 这个方法
// 实际上就是 首地址 看偏移多少,前面总共 16 (isa== 8, flag == 4, reservaed == 4)
void *pBlcok = (__bridge void *)block;
// 这个 加 2, ???
void (*invoke)(void *, ...) = *((void **)pBlcok + 2);
invoke(pBlcok); // 传第一个参数
}
- 6、利用 Clang 中一些节点,完全懵的
static void blcokCleanUp(__strong void(^*block)(void)) {
(*block)();
}
- (void)blcokProblemAnswerSix:(void(^)(void))block {
__strong void(^cleaner)(void) __attribute ((cleanup(blcokCleanUp),unused)) = block;
}
- 7、内联一个汇编 完成调用,完全醉了
- (void)blcokProblemAnswerSeven:(void(^)(void))block {
// block(); // dis 找到其 方法的来源
asm("callq *0x10(%rax)");
}
这真的是大开眼界啊,个人第一种和第二种还能接受,第三种和第五种是想要掌握,其他的还是看看吧,确实是涨知识啦!!!像 NSInvocation 就得立马去补补啦!
PS1: class 关键词用于 property 的新特征 , 表示类的属性,和 Swift 桥接的。
@interface TestObject : NSObject
@property (nonatomic, class) TestObject *shareObject; // 尽量让其访问权限最小
@end
可以更好的写单例
// 写单例,都可以直接, 这样写啦
+ (TestObject *) shareObject {
}
PS2: DLIntrospection 一个很赞的工具
可以获取 NSObject 的 属性、方法、继承结构之类的 ,看Sunny 用的很爽。
3、iOS进阶的话题
单靠知识点累计还不行,需要有自己的思考,对技术的主见
将各个知识点串联起来形成自己的东东。
对于我个人来说,对我很有启发的是:
- 写文章可以用点代替面,注意积累
- 丁字领域说法不错,发展一门深的,其他的都融会贯通啦
- 对于知识点的深挖,挖到自己不能再挖为止,后期还得经常反思、串联,然后形成自己体系。
而我最大的问题,就是每次浅尝即止,没能刨根问底!
另外Sunny 的说:写博客就要写别人没写过的,我想对于我来说是有待商榷的,个人应该是说写博客要追求别人没写过的!毕竟目前还是以记笔记为主,希望得先积累多一些点吧!
最后,Sunny 为大家带来了福利,之前的视频下载地址,包括 他之前 Clang 和 RunLoop 的视频,,非常赞,也非常感谢!