今日头条的iOS高级开发岗第三面,下面记录这次面试的回忆以作日后复习。
简单介绍一下你自己吧
讲讲下你在你项目中做过的优化或者技术难点
1) 编写一个自定义类:Person,父类为NSObject
@interface Person:NSObject
2) 该类有两个属性,外部只读的属性
name
,还有一个属性age
name
的修饰符nonatomic
,strong
,readonly
。age
的修饰符nonatomic
,copy
。3) 为该类编写一个初始化方法
initWithName:(NSString *)nameStr
,并依据该方法参数初始化name
属性。
4) 如果两个Person类的name相等,则认为两个Person相等
isEqual
,这里面涉及到了哈希函数在iOS中的应用。题目: 怎样实现外部只读的属性,让它不被外部篡改
解析:
self.ivar = @"aa";
只能使用实例变量_ivar = @"aa";
,而外界想要修改只读属性的值,需要用到kvc赋值[object setValue:@"mm" forKey:@"ivar"];
。题目: nonatomic是非原子操作符,为什么要这样,atomic为什么不行?有人说能atomic耗内存,你觉得呢?保读写安全吗,能保证线程安全吗?有的人说atomic并不能保证线程安全,你觉得他们的出发点是什么,你认同这个说法吗?
如果该对象无需考虑多线程的情况,请加入这个属性修饰,这样会让编译器少生成一些互斥加锁代码,可以提高效率。
而atomic这个属性是为了保证程序在多线程情况下,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题。
atomic 和 nonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。如果你自己写 getter/setter,那 atomic/nonatomic/retain/assign/copy 这些关键字只起提示作用,写不写都一样。
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
苹果的官方文档 有解释,下面我们举例子解释一下背后的原理。
//@property(nonatomic, retain) UITextField *userName;
//系统生成的代码如下:
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
//@property(retain) UITextField *userName;
//系统生成的代码如下:
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName release];
userName = [userName_ retain];
}
}
简单来说,就是 atomic 会加一个锁来保障多线程的读写安全,并且引用计数会 +1,来向调用者保证这个对象会一直存在。假如不这样做,如有另一个线程调 setter,可能会出现线程竞态,导致引用计数降到0,原来那个对象就释放掉了。
atomic修饰的属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。
因为atomic修饰的属性靠编译器自动生成的get和set方法实现原子操作,如果重写了任意一个,atomic关键字的特性将失效
题目: 你在初始化的方法中为什么将参数赋给_name,为什么这样写就能访问到属性声明的示例变量?
@synthesize name = _name
的代码,不再需要手写,避免了“体力代码”的手动编码题目: 初始化方法中的_name是在什么时候生成的?分配内存的时候吗?还是初始化的时候?
题目: 作为return的self是在上面时候生成的?
- (instancetype)initWithDistance:(float)distance maskAlpha:(float)alpha scaleY:(float)scaleY direction:(CWDrawerTransitionDirection)direction backImage:(UIImage *)backImage {
if (self = [super init]) {
_distance = distance;
_maskAlpha = alpha;
_direction = direction;
_backImage = backImage;
_scaleY = scaleY;
}
return self;
}
题目: 为什么用copy,哪些情况下用copy,为什么用copy?
setName:
传进一个nameStr参数,那么有了copy修饰词后,传给对应的成员变量_name的其实是[nameStr copy];
。strong
修饰的NSString类型的name属性,传一个NSMutableString:NSMutableString *mutableString = [NSMutableString stringWithFormat:@"111"];
self.myString = mutableString;
在strong
修饰下,把可变字符串mutableString赋值给myString后,改变mutableString的值导致了myString
值的改变。而copy
修饰下,却不会有这种变化。
在strong
修饰下,可变字符串赋值给myString后,两个对象都指向了相同的地址。而copy
修饰下,myString和mutableString指向了不同地址。这也是为什么strong修饰下,修改mutableString引起myString变化,而copy修饰下则不会。
题目: 分类中添加实例变量和属性分别会发生什么,编译时就报错吗,还是什么时候会发生问题?为什么
1) 你平时有做过优化内存的哪些工作?怎样避免内存消耗的大户?
2) 你怎样实现线程安全的?这些线程安全的办法和atomic有什么不一样?atomic的实现机制是怎样
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。