前言面试
1. #import和#include的区别?设计模式
参考答案:api
#import是Objective-C导入头文件的语法,可保证不会重复导入。数组
#include是C/C++导入头文件的语法,若是是Objective-C与C/C++混编码,对于C/C++类型的文件,仍是使用#include来引入,这种写法须要添加防重复导入的语法。安全
2. @class的做用多线程
参考答案:架构
@class通常用于头文件中经过前向声明,就能够声明了,可是在.m文件中仍是须要使用#import进来的。它的做用只是前向声明。并发
3. 用NSLog函数输出一个浮点类型,结果四舍五入,并保留一位小数框架
参考答案:
float money = 1.011;
NSLog(@"%.1f", money);
使用%f来格式化,其中要保留一位小数,所以再用%.1f就是保留一位。
4.property属性的修饰符有什么样的做用
参考答案:
property是属性访问声明,扩号内支持如下几个属性:
getter=getName、setter=setName:设置setter与getter的方法名
readwrite、readonly:设置可供访问级别
assign:方法直接赋值,不进行任何retain操做,为了解决原类型与环循引用问题
retain:其setter方法对参数进行release旧值再retain新值,全部实现都是这个顺序
copy:其setter方法进行copy操做,与retain处理流程同样,先对旧值release,再copy出新的对象,retainCount为1。这是为了减小对上下文的依赖而引入的机制。
nonatomic:非原子性访问,不加同步, 多线程并发访问会提升性能。注意,若是不加此属性,则默认是两个访问方法都为原子型事务访问。
5. self.name=@object和name=@object有什么不一样?
参考答案:
self.name =”object”:会调用对象的setName()方法;name = “object”:会直接把"object"字符串赋值给当前对象的name属性。
6. viewDidLoad、loadView和viewDidUnload什么时候调用
参考答案:
viewDidLoad在view加载完成时调用,loadView在controller的view为nil时调用。对于viewDidUnload如今已经不能直接调用了。
7. objective-c中的可变与不可变词典
参考答案:
可变字典就是能够增、删、改操做的字典,对应于NSMutableDictionary类型。
不可变字典就是不能执行增、删、改操做的字典,对应于NSDictionary类型。
8.Objective-C的内存管理
参考答案:
如今内存管理几乎都采用ARC,也就是Automatic Reference Counting,意思是自动引用计数。由编译器在编译时自动为添加retain、release等代码。
若是问的MRC,也就是Manual Reference Counting,意思是手动内存管理。
黄金法则:谁使对象的引用计数+1,再也不使用该对象时,谁就应该使该对象的引用计数-1。
9. 自动生成getter/setter方法
参考答案:
对于之前的代码,那时尚未property,使用这样的方法来建立:
- (void)setName:(NSString *)aName;
- (NSString *)name;
在后面有了property,直接使用@property (nonatomic, copy) NSString *name这样的方法来声明,编译器会自动生成getter/setter方法并生成一个_name成员变量。
10. 什么是MVC
参考答案:
我相信大部分人在被问到这个问题时,都会回答M就是Model,V就是View,C就是Controller。这都是停留在概念上的回答,明显没有什么工做经验。对于一个对框架和架构有必定的思想的人,回答时会从项目的耦合度、团队开发如何减小冲突、如何下降团队与团队之间的沟通成本、如何将M、V、C之间按照既定的标准创建沟通的桥梁。
Model用于处理数据,一般来讲,Model中会包含多个字段,用于存储数据。可是,Model还会有一部分逻辑,好比说:
@interface TestModel: HYBBaseModel
// 这个是接口返回的字段,1表示XXX,2表示YYY,3表示ZZZ
@property (nonatomic, assign) NSUInteger type;
// 这个不是接口返回的字段,可是因为`type`字段是一个数值,不是`view`须要显示的数据
// 因此咱们最好将逻辑统一放到这里来,外部只管获取最终显示须要的值便可。即便哪天接口
// 返回的字段变化或者增长什么新的值,只须要处理这个模型内部就行了。
@property (nonatomic, copy, readonly) NSString relationship;
@end
对于View,不该该包含逻辑,应该根据模型直接获取数据。
对于Controller,大部分交互逻辑都集中到了这里,全部View须要的数据,都是经过Controller提取Model而后交给view去显示数据。
11. 重写getter/setter方法
假设声明属性:
@property (nonatomic, copy) NSString *blogName;
重写这个属性的getter/setter方法:
参考答案:
这里一旦连getter方法也重写,编译器不会给咱们自动生成成员变量_blogName,所以咱们须要在类的声明中添加一个成员变量_blogName:
@interface Demo () {
NSString *_blogName;
}
@end
在自动内存管理下(ARC):
- (void)setBlogName:(NSString *)aName {
if (_blogName != aName) {
_blogName = nil;
_blogName = [aName copy];
}
}
- (NSString *)blogName {
return _blogName;
}
对于手动内存管理(MRC):
- (void)setBlogName:(NSString *)aName {
if (_blogName != aName) {
[_blogName release];
_blogName = nil;
_blogName = [aName copy];
}
}
- (NSString *)blogName {
return _blogName;
}
12. obj在编译时和运行时分别时什么类型的对象
以下面的代码,obj在编译时和运行时分别时什么类型的对象:
NSString *obj = [[NSData alloc] init];
参考答案:
在编译时,咱们所声明的obj是NSString *类型,所以是NSString类型对象。在运行时,因为指针obj所指向的是NSData类型对象的内存,所以其实是NSData类型的对象。在编译时,这一行代码会转换成相似这样:
NSString *obj = ((id (*)(id, SEL))objc_msgSend)([NSData class], @selector(alloc));
obj = ((id (*)(id, SEL))objc_msgSend)((id)obj, @selector(init));
因为在编译时,转换成id,所以能够用NSString *指向NSData对象,而id是具有运行时特性的,所以在连接时,经过id的isa指针能够找到其所属的类,所以最终类型仍是经过isa肯定其所属类型。
13. id声明的对象有什么特性?
id类型能够指向任何类型的对象。
参考答案:
咱们先看看其定义:
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
可其定义可知id类型是一个指向objc_object结构体类型的指针,这个结构体只有一个指向对象无类的指针isa,所以id能够指向任何类型的对象,故其具有运行时特性。
14. iOS设备性能测试
在实际开发中,咱们常常须要对应用瘦身,所以对性能的检测是很重要的。
参考答案:
使用Profile-> Instruments ->Time Profiler能够检测性能。
15. Objective-C中有私有方法、私有变量么?
我记得曾经我就被这么问过,不知道你们有没有遇到过。
参考答案:
在类的.m实现文件内声明,就能够做为私有方法、私有变量。可是,并非绝对的私有,若是外部知道有这么个方法,同样能够调用,并且不会报错。就像苹果公司没有公开出来的API,只要咱们经过其它方式了解到api就能够调用。因而苹果审核时常常因为使用了私有api而打回来了。
16. 简述tableview的重用机制
曾经笔者面试时,也被问到这个问题。
参考答案:
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]
这个方法就是重用机制的核心了。好比,有一个界面可显示10个cell,那么建立10次cell,并给cell指定一样的重用标识(固然,能够为不一样显示类型的cell指定不一样的标识)而且10个cell将所有都加入到visiableCells数组,reusableTableCells为空.
滚动tableView,当有一个cell彻底移出屏幕时,这个cell就会被加入到reusableTableCells。而新出现的那个cell将加入到visiableCells,而这个cell就是被重用的。
若是要让tableview不重用,不设置reuseIdentifier就能够了。
17. nil与NULL的区别
参考答案:
nil和C语言的NULL相同,在objc/objc.h中定义。nil表示Objective-C对象的值为空。在C语言中,指针的空值用NULL表示。在Objective-C中,nil对象调用任何方法表示什么也不执行,也不会崩溃。
18. Category是什么,什么时候使用?
参考答案:
Category就是所谓的扩展。
有时咱们须要在一个已经定义好的类中增长一些方法,而不想去重写该类,这时候使用扩展就很好。好比,当工程已经很大,代码量比较多,或者类中已经有不少方法,已经有其余代码调用了该类建立对象并使用该类的方法时,可使用类别对该类扩充新的方法。
笔者所到公司之处,都会根据公司的UI风格定制一套UI组件,统一全局的风格。本人向来不喜欢用xib/storyboard开发,由于维护成本过高了。咱们不能经过继承的方式定制各类组件吧?因此这个时候使用扩展是最佳时期.
19. 什么是Delegate?经常使用场景?
参考答案:
Delegate就是所谓的代理,代理是一种设计模式。在iOS开发中,会使用到大量的代理,而代理设计模式是苹果中的标准设置模式。
经常使用场景有反向传值。好比:苹果的蓝牙,咱们进入到下一个界面去打开或者关闭蓝牙,当操做以后须要将状态反馈到前一个界面,并更新显示。对于这种状态,使用代理设计模式是很标准的模式。
20. 什么是单例,如何设计单例?
参考答案:
单例就是全局都只有一个对象存在,并且是在整个App运行过程当中都存在。每一个App都会有单例,好比UIApplication。而咱们在作用户数据存储时,一般都会用单例存储,由于应用在全部操做中,常常要求先登陆。
下面这种写法是最经常使用的写法,这个是线程安全的。
+ (instancetype)shared {
static HYBUserManager *sg_userManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (sg_userManager == nil) {
sg_userManager = [[HYBUserManager alloc] init];
}
});
return sg_userManager;
}
21. 什么是通知?
参考答案:
在iOS中,通知是很是经常使用的设计模式。它是多对多的关系。关于通知,因为这一节比较重要,单独写成一篇文章,后续发出!
写在最后
文章中不免有说得不合理的地方,若是您认为说法不正确或者哪里有错误的地方,请在评论中留言,笔者会在第一时间修正!!!