转载极客头条的ios面试题

来源:互联网 发布:cp什么意思网络用语 编辑:程序博客网 时间:2024/05/22 14:00

代码规范


风格纠错原题:

1

以下是我的的修正版本:

2

一个区分很大的面试题


  • @property 后面可以有哪些修饰符?

    • 线程安全:nonatomicatomic
    • 内存管理: strongweak ,copy,retain,unsafe_unretained,assign
    • 访问权限:readonlyreadwrite
    • 指定方法名:getter=setter=
    • 不常用的:nonnull,null_resettable,nullable
  • 什么情况使用 weak 关键字,相比 assign 有什么不同?

    • 在ARC下使用block引起循环引用时,需要使用weak。
    • 属性使用IBOutlet时,使用weak关键字修饰。
    • assign用于简单的赋值,不改变属性的引用计数,用于Objective-C中的NSInteger, CGFloat。以及C语言中的int, float, double等数据类型。
    • weak用于对象类型,同样不改变对象的引用计数且不持对象。当该对象废弃时,该弱引用失效并自动的将指针变量赋值为nil,可以避免循环引用。
  • 怎么用 copy 关键字?

    • 一般使用retain或者strong修饰属性时,是使引用对象的指针指向同一个对象,即为同一块内存地址。只要其中有一个指针变量被修改时所有其他引用该对象的变量都会被改变。
    • 而使用copy关键字修饰在赋值时是释放旧对象,拷贝新对象内容。重新分配了内存地址。以后该指针变量被修改时就不会影响旧对象的内容了。
    • copy只有实现NSCopying协议的对象类型才有效。
    • 常用于NSString和Block。
  • 这个写法会出什么问题:@@property (copy) NSMutableArray *array;

    当一个NSMutableArray对象使用initWithArray:初始化方法创建时,并将该对象赋值给了array属性。那么之后array执行可变数组的方法,比如: removeObjectAtIndex:时会出现unrecognized selector sent to instance的崩溃。原因在于array属性在被赋值(setter)的时候默认执行了copy方法后变为了不可变NSArray对象。

  • 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

    • 该类必须要实现NSCopying协议。实现 - (id)copyWithZone:(NSZone *)zone;方法。
    • 重写copy关键字的setter时,需要调用一下传入对象的copy方法。然后赋值给该setter的方法对应的成员变量。

这一套问题区分度比较大,如果上面的问题都能回答正确,可以延伸问更深入点的

  • @property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的.

    property在编译时编译器会自动的为我们生成一个私有的成员变量和setter与getter方法的声明和实现。反编译property大致生成五个东西

    • OBJCIVAR$类名$属性名称 该属性的偏移量
    • setter与getter方法对应的实现函数
    • ivar_list 就是成员变量列表
    • method_list 方法列表
    • prop_list 属性列表
      也就是说我们每次在增加一个属性,系统都会在ivar_list中添加一个成员变量的描述,在method_list中增加setter与getter方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后产生setter与getter方法对应的实现,在setter方法方法中从偏移量的位置开始赋值,在getter方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。
  • @protocol 和 category 中如何使用 @property

    • 在protocol中使用property只会生成setter和getter方法声明,我们使用属性的目的,是希望遵守我协议的对象的实现该属性
    • category 使用 @property 也是只会生成setter和getter方法的声明,如果我们真的需要给category增加属性的实现,需要借助于运行Objective-C动态运行机制中的两个函数:
      • objc_setAssociatedObject
      • objc_getAssociatedObject
  • runtime 如何实现 weak 属性

    // 模拟代码id obj1;obj1 = 0;objc_storeWeak(&obj1, obj);objc_storeWeak(&obj1);

objc_storeWeak函数把第二个参数的赋值对象的地址作为键值,将第一个参数的weak修饰的属性变量的地址注册到weak表中。如果第二个参数为0,那么把变量的地址从weak表中删除,在后面的相关一题会详解。

CheckList


[※]@property中有哪些属性关键字?

同上

[※]weak属性需要在dealloc中置nil么?

不需要,在ARC环境无论是强指针还是弱指针都无需在dealloc设置为nil,ARC会自动帮我们处理.

[※※]@synthesize和@dynamic分别有什么作用?

  • @property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = var,var为property变量。可以手动修改属性var对应的实例变量。例如:@syntheszie var =var1
  • @synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法, 在Xcode4.4之后的版本可以省略不写.
  • @dynamic告诉编译器不要自动生成成员变量的getter和setter方法,而是开发者自己手工生成或者运行时生成.

[※※※]ARC下,不显示指定任何属性关键字时,默认的关键字都有哪些?

  • 基本数据类型:atomicreadwrite``,assign`
  • 普通的Objective-C对象:atomic,readwrite,strong

[※※※]用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

  • 使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
  • 如果使用strong.这个属性有可能指向一个可变对象,如果这个可变对象被外部意外的修改了,由于可变对象被改变之后起始地址不会发生变化。而附有strong修饰的属性依然指向这这块内存地址,下次读取的时候就会是被改变以后的对象了.也就是说如果使用strong可能会被外部意外的修改。

[※※※]@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

如果没有指定实例变量的名称,就会默认自动生成一个与属性同名的并在前面加一条下划线的实例变量.
如果指定了实例变量名称,刚好与属性自动合成的实例变量名称相同,那就该属性就不自动合成实例变量了。
默认的是 @synthesize foo = _foo; 属性就不会自动生成实例变量了.
如果使用 @synthesize foo = _foo1; 属性不会自动生成实例变量,而且成员变量被修改为_foo1, 使用点语法set属性成员变量的值会赋值给_foo1,而不是_foo.

[※※※※※]在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?

@synthesize主要就是用来生成setter,getter方法的实现,在@property被增强之后,已经很少使用@synthesize了.

[※※]objc中向一个nil对象发送消息将会发生什么?

objc向nil发送消息是有效的,只是在运行时不会有什么作用.

  • 如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。
  • 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者long long的整型标量,发送给nil的消息将返回0。
  • 如果方法返回值为结构体,发送给nil的消息将返回0。结构体中各个字段的值将都是0。
  • 如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。

[※※※]objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

[obj foo]变量编译之后就是objc_msgSend()函数的调用。该方法编译后的形式大致如下:
objc_msgSend(obj, sel_registerName(“foo”));

[※※※]什么时候会报unrecognized selector的异常?

当类或者对象使用到某个声明过的方法,而这个方法不管自己类还是在父类里都没有实现的时候。

[※※※※]一个objc对象如何进行内存布局?(考虑有父类的情况)

每一个objc对象都是一个类的实例。在Objective-C语言的内部,每一个对象都有一个名为isa的指针,指向该对象的类(类对象)。每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。每一个对象都可以接受消息,而对象能够接收的消息列表是保存在它所对应的类对象中。如下图:

3

类对象内部还有一个指向superclass的指针,指向他的父类对象,根类为NSObject类它的superclass指针指向nil,如下图:

4

类对象既然称为对象那它也是一个实例。类对象中也有一个isa指针指向它的元类(meta class),即类对象是元类的实例。元类内部存放的是类方法列表,根元类的isa指针指向自己,superclass指针指向NSObject类。

[※※※※]一个objc对象的isa的指针指向什么?有什么作用?

objc对象的isa指针指向类对象,用于寻找对象的方法。

[※※※※]下面的代码输出什么?

@ implementation Son : Father- (id)init{    self = [super init];    if (self) {        NSLog(@"%@", NSStringFromClass([self class]));        NSLog(@"%@", NSStringFromClass([super class]));    }    return self;}@ end

输出的都是:Son

[※※※※]runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)

每一个类对象中都一个方法列表,方法列表中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.

[※※※※]使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

  • 在ARC下不需要
  • 在MRC中,对于使用retain或copy策略的时候需要释放

[※※※※※]objc中的类方法和实例方法有什么本质区别和联系?

类方法

  • 类方法保存在类对象的元类中
  • 类方法只能通过类对象调用
  • 类方法中的self是类对象
  • 类方法中不能访问成员变量
  • 类方法中不能直接调用对象方法

实例方法

  • 保存在类对象的对象模型中
  • 实例方法只能通过实例对象调用
  • 实例方法中的self是实例对象
  • 实例方法中可以访问成员变量
  • 实例方法中可以访问成员变量
  • 实例方法中可以访问成员变量

[※※※※※]_objc_msgForward函数是做什么的,直接调用它将会发生什么?

这个没接触过,也没找到相关资料。但是跟objc动态运行机制中的forwardingTargetForSelector:forwardInvocation:方法有点相似。猜测是该方法编译后的源码,都用于消息转发机制。

[※※※※※]runtime如何实现weak变量的自动置nil?

/* 编译器的模拟源代码 */ id obj1; objc_initWeak(&obj1, obj); objc_destroyWeak(&obj1);

通过objc_initWeak函数初始化附有weak修饰符的变量,在变量作用域结束时通过objc_destoryWeak函数释放该变量。objc_initWeak函数将附有weak修饰符的变量初始化为0后,将会赋值的对象作为参数调用objc_storeWeak函数。

obj1 = 0;obj_storeWeak(&obj1, obj);

然后obj_destroyWeak函数将0作为参数的调用objc_storeWeak函数。

obj_destroyWeak(&obj1, 0);

前面的源代码与下列源代码相同。

/ * 编译器的模拟代码 */id obj1;obj1 = 0;objc_storeWeak&obj1, obj);objc_storeWeak(&obj1, 0);

objc_storeWeak函数的第二参数的赋值对象的地址作为键值,将第一个参数的附有__weak修饰符的变量的地址注册到weak表中。如果第二参数为0,则把变量的地址从weak表中删除。

[※※※※※]能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

  • Objective-C不支持往已存在的类中添加实例变量
    • 可以向运行时创建的类中添加实例变量。参考

[※※※]runloop和线程有什么关系?

  • runloop是线程的基础架构。每个线程,包括程序的主线程(main thread)都有与之相应的run loop对象.
  • 主线程的runloop默认是启动的。
  • 对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动.
  • 可以通过NSRunLoop的currentRunLoop类方法来获取当前线程的runloop

[※※※]runloop的mode作用是什么?

*NSDefaultRunLoopMode 缺省情况下,将包含所有操作,并且大多数情况下都会使用此模式

  • NSConnectionReplyMode 此模式用于处理NSConnection的回调事件
  • NSModalPanelRunLoopMode 模态模式,此模式下,RunLoop只对处理模态相关事件
  • NSModalPanelRunLoopMode 此模式用于处理NSConnection的回调事件
  • NSRunLoopCommonModes 此模式用于配置”组模式”,一个输入源与此模式关联,则输入源与组中的所有模式相关联。

[※※※※]以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

  • 当前主线程的 RunLoop 正在以 UITrackingRunLoopMode的模式运行。 这个时候 RunLoop 只会处理与UITrackingRunLoopMode “绑定”的源, 比如触摸、滚动等事件;而 NSTimer 是默认“绑定”到 NSRunLoopDefaultMode 上的, 所以 Timer 是事情是不会被 RunLoop 处理的,定时器被暂停了!
  • 常见的解决方案是把Timer“绑定”到 NSRunLoopCommonModes模式上:
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

>
这样这个Timer就可以和当前组中的两种模式 UITrackingRunLoopMode 和 kCFRunLoopDefaultMode相关联了。 RunLoop在这两种模式下,Timer都可以正常运行了。

[※※※※※]猜想runloop内部是如何实现的?

*runloop是一个死循环

  • 如果事件队列中存放在着事件,就会取出事件执行。
  • 如果没有事件,就挂起,等有事件了,唤醒循环,开始执行.

[※]objc使用什么机制管理对象内存?

  • MRC 手动引用计数
  • ARC 自动引用计数

[※※※※]ARC通过什么方式帮助开发者管理内存?

在编译器编译器为开发者添加内存管理的代码。

[※※※※]不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vc的viewDidLoad中创建)

  • 在每次事件循环开始创建自动释放池,在每次事件结束销毁自动释放池.
  • 在viewDidLoad中创建的,是在viewWillAppear和viewDidApper之间系统执行[pool drain]操作的时候释放对象的。

[※※※※]BAD_ACCESS在什么情况下出现?

  • 对一个已经释放的对象执行了release
  • 执行了死循环

[※※※※※]苹果是如何实现autoreleasepool的?

autoreleasepool以一个队列数组的形式实现,主要通过下列三个函数完成.

  • objc_autoreleasepoolPush
  • objc_autoreleasepoolPop
  • objc_aurorelease

看函数名就可以知道,对autorelease分别执行push,和pop操作。销毁对象时执行release操作。

[※※]使用block时什么情况会发生引用循环,如何解决?

一个对象中强引用了block,在block中又使用了该对象,就会发射循环引用。
解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。

  1. id weak weakSelf = self;
    或者 
    weak __typeof(&*self)weakSelf = self该方法可以设置宏
  2. id __block weakSelf = self;

[※※]在block内如何修改block外部变量?

外部变量使用__block修饰

[※※※]使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?

一般不用考虑,因为官方文档中没有告诉我们要注意发生强引用,所以推测系统控件一般没有对这些block进行强引用,所以我们可以不用考虑循环强引用的问题

[※※]GCD的队列(dispatch_queue_t)分哪两种类型?

  • 串行队列Serial Dispatch Queue
  • 并行队列Concurrent Dispatch Queue

[※※※※]如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, queue, ^{ /*加载图片1 */ });dispatch_group_async(group, queue, ^{ /*加载图片2 */ });dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{        // 合并图片});

[※※※※]dispatch_barrier_async的作用是什么?

dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue并行队列中的操作全部执行完之后,然后再执行dispatch_barrier_async函数追加的处理,等dispatch_barrier_async追加的处理执行结束之后,Concurrent Dispatch Queue才恢复之前的动作继续执行。

打个比方:比如你在看电视每个台都在播放精彩的内容,突然插进来一则广告。于是你就换台,结果发现每个台都在放这个广告,等这个广告播放完之后,各个台才开始恢复原来播放的内容。dispatch_barrier_async函数追加的内容就如这条广告。

[※※※※※]苹果为什么要废弃dispatch_get_current_queue?

dispatch_get_current_queue容易造成死锁

[※※※※※]以下代码运行结果如何?

- (void)viewDidLoad{    [super viewDidLoad];    NSLog(@"1");    dispatch_sync(dispatch_get_main_queue(), ^{        NSLog(@"2");    });    NSLog(@"3");}

只输出:1 。发生主线程锁死。

[※※]addObserver:forKeyPath:options:context:各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调?

   // 添加键值观察    /*     1 观察者,负责处理监听事件的对象     2 观察的属性     3 观察的选项     4 上下文     */[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];

observer中需要实现一下方法:

// 所有的 kvo 监听到事件,都会调用此方法/* 1. 观察的属性 2. 观察的对象 3. change 属性变化字典(新/旧) 4. 上下文,与监听的时候传递的一致 */- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 

[※※※]如何手动触发一个value的KVO

给这个value设置一个值,就可以触发了

[※※※]若一个类有实例变量NSString *_foo,调用setValue:forKey:时,可以以foo还是_foo作为key?

都可以

[※※※※]KVC的keyPath中的集合运算符如何使用?

  • 必须用在集合对象上或普通对象的集合属性上
  • 简单集合运算符有@avg, @count , @max , @min ,@sum,
  • 格式 @”@sum.age”或 @”集合属性.@max.age”

[※※※※]KVC和KVO的keyPath一定是属性么?

  • KVO支持实例变量

[※※※※※]如何关闭默认的KVO的默认实现,并进入自定义的KVO实现?

如何自己动手实现 KVO

[※※※※※]apple用什么方式实现对一个对象的KVO?

上一题已包含

[※※]IBOutlet连出来的视图属性为什么可以被设置成weak?

因为既然有外链那么视图在xib或者storyboard中肯定存在,视图已经对它有一个强引用了。

[※※※※※]IB中User Defined Runtime Attributes如何使用?

它能够通过KVC的方式配置一些你在interface builder 中不能配置的属性。当你希望在IB中作尽可能多得事情,这个特性能够帮助你编写更加轻量级的viewcontroller

[※※※]如何调试BAD_ACCESS错误

  • 重写object的respondsToSelector方法,现实出现EXEC_BAD_ACCESS前访问的最后一个object
  • 通过NSZombieEnabled
  • 设置全局断点快速定位问题代码所在行

[※※※]lldb(gdb)常用的调试命令?

  • breakpoint 设置断点定位到某一个函数
  • n 断点指针下一步
  • po打印对象

本文由程序员头条管理员蒋小飞原创文章,转载务必注明出处。

0 0
原创粉丝点击