iOS面试总结

前段时间辞职了,因为公司的气氛十分的压抑,而且公司没有一个合格的产品经理,没有明确的产品路线,完全是走一步看一步,几乎除了研发全是副总,而且每此投资人员一来公司,App肯定会有改动,当然有大有小,每次刚刚做好的东西瞬间就会改掉,有得时候一天会改七八次。在这样的没有明确目标的公司做一款产品,我丝毫感觉不到希望,对公司的理念完全失去了兴趣。在这个公司编程变成了一件枯燥的事情,这根本不是我想要的生活,我不想干了,重要的是失去了感觉和编程的乐趣。(真的是这样,乐趣的确很重要,乔布斯都这么说)。
知之者不如好之者,好之者不如乐之者。五千年前孔子已经道出了成功的境界之所在,当你成为一名乐之者的时候,事实上已经把工作当成了玩,就像玩游戏打怪升级一样,很有快感和成就感。当你沉浸在一件事情的时候,你就很容易吧这件事情做好,因为你的兴趣在这件事情上,你乐意去完成它,即便有困难,我想你也乐意去解决。
好的扯得有点远了,PS:哪位的公司愿意收留请私信我,下面我来贴出来我面试的时候遇到的面试题。

第1题
@implementation Son : Father
- (id)init{ self = [super init];
   if (self) {
      NSLog(@"%@", NSStringFromClass([self class]));  
      NSLog(@"%@", NSStringFromClass([super class]));
      NSLog(@"%@",NSStringFromClass(self.superclass));
   }
 return self;
}
@end
//打印结果就是
Son
Son
Father
我来告诉大家为什么
当 发送 class 消息 时不管是 self  还是 super 其消息主体依然是  self ,也就是说 self 和 super 指向的 是同一个对象。只是 查找方法的位置 区别,一个从本类,一个从本类的超类。
一般情况下  class 方法 只有在 根类 NSObject 中定义,极少情况有子类重写 class 方法,
所以  [self  class] 和 [super class] 都是在 根类中 找方法实现, 消息接收主体 又都是 a
如果重写可能会不一样。
自然都打印出  Son 
第2题

UIView、UIWindow和CALayer的联系和区别

UIView负责渲染矩形区域内的内容,为矩形区域添加动画,相应区域的触摸事件,布局, 和管理一个或多个子视图,UIWindow是一个特殊的UIView,通常在一个程序中只有一个UIWindow,但可以手动创建多个添加到程序中
UIWindow主要起三个作用:
1、作为容器,包含程序所有要显示的视图
2、传递触摸消息到其他的UIView或其他对象
3、与UIViewController协同工作,完成设备方向旋转的支持
CALayer是绘制内容的,不处理事件响应,与UIView是相互依赖的,依赖于UIView来显示绘制内容,UIView依赖于CALayer来提供内容```
######第3题
#import、@class、#include联系和区别?
通常引用一个类有两种办法:
一种是通过#import方式引入;另一种是通过@class引入;
这两种的方式的区别在于:
1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息;
 
2、使用@class方式由于只需要只要被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用#importl来包含被引用类的头文件;
 
3、通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一 个文件,或者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了;

由上可知,@class是放在interface中的,只是在引用一个类,将这个被引用类作为一个类型,在实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。

预编译指令
Objective-C:#import
C,C++:#include
#import由gcc编译器支持
在 Objective-C 中,#import 被当成 #include 指令的改良版本来使用。除此之外,#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。
使用哪一个还是由你来决定。一般来说,在导入 Objective-C 头文件的时候使用 #import,包含 C 头文件时使用 #include。比如:

#import比起#include的好处就是不会引起交叉编译
######第4题
OC中的属性修饰符,查看一下[博文](http://blog.sina.com.cn/s/blog_83b365f60102w70n.html),写的很清楚。

######第5题
![](http://upload-images.jianshu.io/upload_images/701353-df72a6147a6477c5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
相信很多人都遇到了这个问题了吧!哈哈,没错我也遇到了,因为是纯看代码,没有Xcode进行实操,所以还是又辣么一点点小难度的。
其实个人感觉这段代码并没有什么太大的错误,只是考考你是不是处女座(换句话说就是考验你的代码规范)
![](http://upload-images.jianshu.io/upload_images/701353-a10b92ff7f6af9e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这是我个人改的,可能每个人的变成习惯不一样,所以答案也不唯一,这道题的初衷大概就是的窥视面试者的编程规范。
这里给出原因,我参考的[博客](http://ios.jobbole.com/82219/)
######第6题
试着定义一个block

typedef void(^selectRowAtIndex)(NSInteger index);
@property (nonatomic, copy)selectRowAtIndex handle;
//其实这些代码要是用Xcode写出来的话我相信有点经验的都可以随手写出来,但是要是写在纸上还是很恶心的一件事,不是么?

反写block:写出下面代码的Block的定义。

[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }
completion:NULL];
答案:
typedef void(^animations) (void);
typedef void(^completion) (BOOL finished);```

第7题

今天被饿了么的工程师问到了个问题,自己觉得回答的不是很好,这里网上查了一下,做了相关的解释,下面贴出来

1、 类别(category)和继承的区别?
*类别:类别是对一个功能完备的类的一种补充,就像是一个东西的主要基本功能都完成了,可以用类别为这个类添加不同的组件,使得这个类能够适应不同情况的需求。比如animal这个类,具有eat和run等方法,想给这个类添加一个bark的方法,可以用类别。

*继承:多个类具有相同的实例变量和方法时,考虑用继承。即子类可以继承父类的相同特性。如animal具有年龄和体重两个属性,dog也具有年龄和体重两 个属性,dog可以继承animal的这两个属性,即为继承。

共同点:都是给一个类进行扩展

区别:
1.类别是对方法的扩展,不能添加成员变量。继承可以在原来父类的成员变量的基础上,添加新的成员变量
2.类别只能添加新的方法,不能修改和删除原来的方法。继承可以增加、修改和删除方法。
3.类别不提倡对原有的方法进行重载。继承可以通过使用super对原来方法进行重载。
4.类别可以被继承,如果一个父类中定义了类别,那么其子类中也会继承此类别。

第8题
__block和__weak修饰符的区别

API Reference对__block变量修饰符有如下几处解释:

//A powerful feature of blocks is that they can modify 
variables in the same lexical scope. You signal that a block 
can modify a variable using the __block storage type 
modifier. 

//At function level are __block variables. These are mutable
 within the block (and the enclosing scope) and are preserved
 if any referencing block is copied to the heap.

大概意思归结出来就是两点:

1.__block对象在block中是可以被修改、重新赋值的。 
2.__block对象在block中不会被block强引用一次,从而不会出现循环引用问题。

API Reference对__weak变量修饰符有如下几处解释:

__weak specifies a reference that does not keep the 
referenced object alive. A weak reference is set to nil when
there are no strong references to the object.

使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题,因为苹果文档已经说的很清楚,当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。

因此,__block和__weak修饰符的区别其实是挺明显的: 
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 
3.__block对象可以在block中被重新赋值,__weak不可以。 
PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
第9题

OC有多继承么?没有的话用什么代替?
其实第一问是废话,为什么这么说,因为很明显看出来这个问题的重点是后半句,所以OC是没有多继承的。但是用什么代替呢?
我们都知道objective C不能像C++一样支持多继承,但是在OC的使用经常会碰到需要使用多继承的情况。例如,ClassA中有methodA,ClassB中methodB,而现在需要使用这两个类中的方法。如何按照C++的编程思路,毫无疑问采用多继承就搞定了,在OC就需要动动脑子了。
笔者最先想到的就是协议,利用协议可以同时实现A + B;
其实我们在学习设计模式的时候知道,多继承的效率不高,而且采用组合的模式可以完全代替继承模式。那么,这种思路完全可以用在OC中实现多继承(或许OC抛弃多继承,就是强迫我们使用更高效的组合设计模式吧!)。上面这种方法是我百度到的,但是也未尝不可,思路就是创建另一个ClassC ,实现一个方法里面包含AB两个方法。但是我觉得这样太繁琐。

其实每一次面试都是一次历练,每一次面试都是一次考验,不管是哪方面,对于一个人的成长都有益处的,就技术知识而言,于我,每次都可以从面试的过程中学到新知识,亦或巩固之前不确定的东西。一次面试让自己发现很多之前没有掌握好的东西,那么这次面试就是有价值的,无论成功与否都是一次成长的机会。
欢迎大牛补充和指点。
欢迎关注我的微博和博客。

你可能感兴趣的:(iOS面试总结)