一个区分度很大的面试题.docx
《一个区分度很大的面试题.docx》由会员分享,可在线阅读,更多相关《一个区分度很大的面试题.docx(11页珍藏版)》请在冰豆网上搜索。
![一个区分度很大的面试题.docx](https://file1.bdocx.com/fileroot1/2022-11/27/77b3c5e2-75d0-4361-8006-46f293dcb0b1/77b3c5e2-75d0-4361-8006-46f293dcb0b11.gif)
一个区分度很大的面试题
一个区分度很大的面试题
考察一个面试者基础咋样,基本上问一个@property就够了:
@property后面可以有哪些修饰符
•线程安全的:
◦atomic,nonatomic
•访问权限的
◦readonly,readwrite
•内存管理(ARC)
◦assign,strong,weak,copy
•内存管理(MRC)
◦assign,retain,copy
•指定方法名称
◦setter=
◦getter=
什么情况使用weak关键字,相比assign有什么不同比如:
•在ARC中,出现循环引用的时候,必须要有一端使用weak,比如:
自定义View的代理属性
•已经自身已经对它进行一次强应用,没有必要在强引用一次,此时也会使用weak,自定义View的子控件属性一般也使用weak;但b是也可以使用strong
•weak当对象销毁的时候,指针会被自动设置为nil,而assign不会*assigin可以用非OC对象,而weak必须用于OC对象
怎么用copy关键字
•对于字符串和block的属性一般使用copy
•字符串使用copy是为了外部把字符串内容改了,影响该属性
•block使用copy是在MRC遗留下来的,在MRC中,方法内部的block是在在栈区的,使用copy可以把它放到堆区.在ACR中对于block使用copy还是strong效果是一样的
这个写法会出什么问题:
@property(copy)NSMutableArray*array;
•添加,删除,修改数组内的元素的时候,程序会因为找不到对于的方法而崩溃.因为copy就是复制一个不可变NSArray的对象
如何让自己的类用copy修饰符
•你是说让我的类也支持copy的功能吗
•如果面试官说是:
◦遵守NSCopying协议
◦实现-(id)copyWithZone:
(NSZone*)zone;方法
•如果面试官说否,是属性中如何使用copy
◦在使用字符串和block的时候一般都使用copy
如何重写带copy关键字的setter
•重写copy的setter方法时候,一定要调用一下传入的对象的copy方法,然后在赋值给该setter的方法对应的成员变量
这一套问题区分度比较大,如果上面的问题都能回答正确,可以延伸问更深入点的:
@property的本质是什么ivar、getter、setter是如何生成并添加到这个类中的
•在普通的OC对象中,@property就是编译其自动帮我们生成一个私有的成员变量和setter与getter方法的声明和实现
•我为了搞清属性是怎么实现的,曾经反编译过相关的代码,他大致生成了五个个东西
•OBJC_IVAR_$类名$属性名称该属性的偏移量
•setter与getter方法对应的实现函数
•ivar_list就是成员变量列表
•method_list方法列表
•prop_list属性列表
•也就是说我们每次在增加一个属性,系统都会在ivar_list中添加一个成员变量的描述,在method_list中增加setter与getter方法的描述,在属性列表中增加一个属性的属性的描述,然后计算该属性在对象中的偏移量,然后伸出setter与getter方法对应的实现,在setter方法方法中从偏移量的位置开始赋值,在getter方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.
@protocol和category中如何使用@property
1在protocol中使用property只会生成setter和getter方法声明,我们使用属性的目的,是希望遵守我协议的对象的实现该属性
2category使用@property也是只会生成setter和getter方法的声明,如果我们真的需要给category增加属性的实现,需要借助于运行时的两个函数
1objc_setAssociatedObject
2objc_getAssociatedObject
runtime如何实现weak属性
runtime对注册的类,会进行布局,对于weak对象会放入一个hash表中。
用weak指向的对象地址作为key,当此对象的引用计数为0的时候会dealloc,进而在这个weak表中找到此对象地址为键的所有weak对象,从而设置为nil
每个人擅长的领域不一样,我们一般会从简历上找自己写擅长的技术聊,假如自己并不是很熟,最好别写出来或扯出来,万一面试官刚好非常精通这里就露馅了。
Checklist
总结过些面试题,没坚持下去,后来把这些当checklist,面试的时候实在没话聊的时候做个提醒,语言、框架、运行机制性质的:
[※]@property中有哪些属性关键字
同上
[※]weak属性需要在dealloc中置nil么
不需要,在ARC环境无论是强指针还是弱指针都无需在deallco设置为nil,ARC会自动帮我们处理
[※※]@synthesize和@dynamic分别有什么作用
1@property有两个对应的词,一个是@synthesize,一个是@dynamic。
如果@synthesize和@dynamic都没写,那么默认的就是@syntheszievar=_var;
2@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
3@dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。
(当然对于readonly的属性只需提供getter即可)。
假如一个属性被声明为@dynamicvar,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到=someVar,由于缺setter方法会导致程序崩溃;或者当运行到someVar=var时,由于缺getter方法同样会导致崩溃。
编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
[※※※]ARC下,不显示指定任何属性关键字时,默认的关键字都有哪些
1对应基本数据类型默认关键字是
2atomic,readwrite,assign
3对于普通的OC对象
4atomic,readwrite,strong
[※※※]用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么如果改用strong关键字,可能造成什么问题
1因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
2如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
[※※※]@synthesize合成实例变量的规则是什么假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么
如果没有指定成员变量的名称与自动生成一个属性同名的成员变量,如果指定的成员变量的名称,会生成一个指定的名称的成员变量,如果这个成员已经存在了就不再生成了.
如果是@synthesizefoo;还会生成一个名称为foo的成员变量
如果是@synthesizefoo=_foo;就不会生成成员变量了.
[※※※※※]在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景
@synthesize主要就是用来生成setter,getter方法的实现,在@property被增强之后,其实已经很少使用@synthesize了,你知道@synthesize的其他使用场景吗能给我介绍一下吗
如果你听懂了,感觉面试官说的很有道理,可以说点赞美的话.
[※※]objc中向一个nil对象发送消息将会发生什么
1在Objective-C中向nil发送消息是完全有效的——只是在运行时不会有任何作用:
◦如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。
例如:
Person*motherInlaw=[aPersonspouse]mother];如果spouse对象为nil,那么发送给nil的消息mother也将返回nil。
◦如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,longdouble或者longlong的整型标量,发送给nil的消息将返回0。
◦如果方法返回值为结构体,发送给nil的消息将返回0。
结构体中各个字段的值将都是0。
◦如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。
[※※※]objc中向一个对象发送消息[objfoo]和objc_msgSend()函数之间有什么关系
该方法编译之后就是objc_msgSend()函数调用.如果我没有记错的大概是这样的.
((void()(id,SEL))(void )objc_msgSend)((id)obj,sel_registerName("foo"));
[※※※]什么时候会报unrecognizedselector的异常
•当该对象上某个方法,而该对象上没有实现这个方法的时候[※※※※]一个objc对象如何进行内存布局(考虑有父类的情况)
•所有父类的成员变量和自己的成员变量都会存放在该对象所对应的存储空间中.
•每一个对象内部都一个isA指针,指向他的类对象,类对象中存放着本对象的对象方法列表和成员变量的列表,属性列表,它内部也有一个isA指针指向元对象(metaclass),元对象内部存放的是类方法列表,类对象内部还有一个superclass的指针,指向他的父类对象
•根对象就是NSobject
•如图:
•
[※※※※]一个objc对象的isa的指针指向什么有什么作用
•指向他的类对象,从而可以找到对象上的方法
[※※※※]下面的代码输出什么
@implementationSon:
Father
-(id)init
{
self=[superinit];
if(self){
NSLog(@"%@",NSStringFromClass([selfclass]));
NSLog(@"%@",NSStringFromClass([superclass]));
}
returnself;
}
@end
输出的结果都是:
Son,
原因:
super和self都是指向的本实例对象的,
不同的是,super调用的跳过本类方法,调用父类的方法
父类方法的class方法本来都是在基类中实现的,所以无论使用self和super调用都是一样的.
具体分析参照刨根问底Objective-CRuntime
(1)-Self&Super
[※※※※]runtime如何通过selector找到对应的IMP地址(分别考虑类方法和实例方法)
•每一个类对象中都一个方法列表,方法列表中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.
[※※※※]使用runtimeAssociate方法关联的对象,需要在主对象dealloc的时候释放么
•在ARC下不需要
•在MRC中,对于使用retain或copy策略的需要
[※※※※※]objc中的类方法和实例方法有什么本质区别和联系
•类方法
◦类方法是属于类对象的
◦类方法只能通过类对象调用
◦类方法中的self是类对象
◦类方法可以调用其他的类方法
◦类方法中不能访问成员变量
◦类方法中不定直接调用对象方法
•实例方法
◦实例方法是属于实例对象的
◦实例方法只能通过实例对象调用
◦实例方法中的self是实例对象
◦实例方法中可以访问成员变量
◦实例方法中直接调用实例方法
◦实例方法中也可以调用类方法(通过类名)
[※※※※※]_objc_msgForward函数是做什么的,直接调用它将会发生什么
1没哟研究过,从名字来看是用来转发消息的,你能给我讲讲吗谢谢!
[※※※※※]runtime如何实现weak变量的自动置nil
1.没有研究过,你有研究过吗,可以给我讲讲吗
2.我猜系统会维护一个弱指针列表,当某个对象销毁时候,它会把所有指向该对象的弱指针设置为nil
[※※※※※]能否向编译后得到的类中增加实例变量能否向运行时创建的类中添加实例变量为什么
因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,同时runtime会调用class_setIvarLayout或class_setWeakIvarLayout来处理strongweak引用。
所以不能向存在的类中添加实例变量,
运行时创建的类是可以添加实例变量,调用class_addIvar函数。
但是得在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上。
[※※※]runloop和线程有什么关系
1.每一个线程中都一个runloop,只有主线的的runloop默认是开启的,其他线程的runloop是默认没有开启的
2.可以通过CFRunLoopRun()函数来开启一个事件循环
3.看SDWebImage源码的时候见到有这么用过.
[※※※]runloop的mode作用是什么
model主要是用来指定时间在运行循环中的优先级的
苹果公开提供的Mode有两个:
kCFRunLoopDefaultMode
kCFRunLoopCommonModes
如果我们把一个NSTimer对象以kCFRunLoopDefaultMode添加到主运行循环中的时候,当一直有用户事件处理的时候,NSTimer将不再被调度
如果我们把一个NSTimer对象以kCFRunLoopCommonModes添加到主运行循环中的时候,当一直有用户事件处理的时候,NSTimer还能正常的调度,互不影响.
[※※※※]以+scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么如何解决
同上
[※※※※※]猜想runloop内部是如何实现的
1.他是一个死循环
2.如果事件队列中存放在事件,那就取出事件,执行相关代码
3.如果没有事件,就挂起,等有事件了,立即唤醒事件循环,开始执行.
简单来说。
。
。
functionloop(){
initialize();
do{
varmessage=get_next_message();
process_message(message);
}while(message!
=quit);
}
[※]objc使用什么机制管理对象内存
*MRC手动引用计数
*ARC自动引用计数,现在通常使用自动引用计数
[※※※※]ARC通过什么方式帮助开发者管理内存
通过编译器在编译的时候,插入如内管理的代码
[※※※※]不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放(比如在一个vc的viewDidLoad中创建)
在每次事件循环开始创建自动释放池,在每次事件结束销毁自动释放池
以viewDidLoad方法为例,可以理解为在viewDidLoad方法开始执行之前创建自动释放池,
在viewDidLoad方法执行之后销毁自动释放吃
[※※※※]BAD_ACCESS在什么情况下出现
1.死循环了
2.访问一个僵尸对象
[※※※※※]苹果是如何实现autoreleasepool的
1.我猜想autoreleasepool本质就是一个队列(数组),
2.当调用autorelease的时候会把该对象添加到autoreleasepool中,并且把引用计数+1
3.当autoreleasepool即将销毁的时候,把其中的所有对象进行一次release操作
[※※]使用block时什么情况会发生引用循环,如何解决
只要是一个对象对该block进行了强引用,在block内部有直接使用到该对象,
[※※]在block内如何修改block外部变量
1通过__bock修改的外部变量,可以在block内部修改
2想装B的话可以说一下__bock内部做了什么事
[※※※]使用系统的某些blockapi(如UIView的block版本写动画时),是否也考虑引用循环问题
一般不用考虑,因为官方文档中没有告诉我们要注意发生强引用,所以推测系统控件一般没有对这些block进行强引用,所以我们可以不用考虑循环强引用的问题
[※※]GCD的队列(dispatch_queue_t)分哪两种类型
串行队列和并行队列
[※※※※]如何用GCD同步若干个异步调用(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
总体上说:
使用dispatchgroup,然后waitforever等待完成,或者采取groupnotify来通知回调。
细节:
1.创建异步队列
2.创建dispatch_groupdispatch_group_t=dispatch_group_create()
3.通过组来执行异步下载任务
dispatch_group_async(queueGroup,aQueue,^{
NSLog(@"下载图片.");
});
4.等到所有任务完成dispatch_group_wait(queueGroup,DISPATCH_TIME_FOREVER);
5.合成图片
[※※※※]dispatch_barrier_async的作用是什么
barrier:
是障碍物的意思,在多个并行任务中间,他就像是一个隔离带,把前后的并行任务分开.
dispatch_barrier_async作用是在并行队列中,等待前面操作并行任务完成再执行dispatch_barrier_async中的任务,如果后面还有并行任务,会开始执行后续的并行任务
[※※※※※]苹果为什么要废弃dispatch_get_current_queue
容易误用造成死锁
[※※※※※]以下代码运行结果如何
-(void)viewDidLoad
{
[superviewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(),^{
NSLog(@"2");
});
NSLog(@"3");
}
1只能输出1,然后线程主线程死锁
[※※]addObserver:
forKeyPath:
options:
context:
各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调
调用对象:
要监听的对象
2.参数
1>观察者,负责处理监听事件的对象
2>观察的属性
3>观察的选项
4>上下文
*/
[addObserver:
selfforKeyPath:
@"name"options:
NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:
@"PersonName"];
观察的属性
2.观察的对象
3.change属性变化字典(新/旧)
4.上下文,与监听的时候传递的一致
可以利用上下文区分不同的监听!
*/
-(void)observeValueForKeyPath:
(NSString*)keyPathofObject:
(id)objectchange:
(NSDictionary*)changecontext:
(void*)context{
NSLog(@"睡会%@",[NSThreadcurrentThread]);
[NSThreadsleepForTimeInterval:
];
NSLog(@"%@%@%@%@",keyPath,object,change,context);
}
[※※※]如何手动触发一个value的KVO
1.通过setValue:
forKey:
给属性赋值
2.通过setValue:
forKeyPath:
给属性赋值
3.直接调用setter方法方法给属性赋值
4.直接通过指针给属性赋值
5.
给这个value设置一个值,就可以触发了
[※※※]若一个类有实例变量NSString*_foo,调用setValue:
forKey:
时,可以以foo还是_foo作为key
都可以
[※※※※]KVC的keyPath中的集合运算符如何使用
1.必须用在集合对象上或普通对象的集合属性上
2.简单集合运算符有@avg,@count,@max,@min,@sum,
3.格式@"@"或@"集合属性"
[※※※※]KVC和KVO的keyPath一定是属性么
1.一个可以是成员变量