iOS面试总结 - 初级篇
1,为什么说Object-C 是一门动态语言?
主要设计两个概念: 运行时与多态,即:对象类型,以及调用对象方法是在运行时决定;可以从三个方面描述,如下:
-
动态类型
对象类型的确定是在运行期间,
如:
id
类型,可以赋不同类型的对象,在运行时决定具体类型;如:
NSData *test = [[NSString alloc] init]
,编译时为NSData类型,运行时为NSString类型;如:父类指针指向子类对象,编译时为类型为父类,运行时为具体子类(简单工厂模式)
-
动态绑定
在运行时决定方法的调用,用于消息发送机制,向某个对象传递消息,就会使用动态绑定机制来决定需要调用的方法;
objc_msgSend
会根据接收者与选择子的类型,在接收者内搜索方法列表,如果找到就响应,本类找不到就沿着继承向上找,最后没有响应会执行消息转发机制;如:多态中的子类重写父类方法,在运行时确定确定调用方法;
如:在
.h
文件声明方法,在.m
不实现方法,让外界调用,编译时不报错,运行时报错; -
动态加载
程序在运行时根据需要在加载可执行的代码和资源;
如:利用
runtime
动态添加属性,添加方法,替换方法;如:不同机型适配,
@2x
,@3x
资源的加载;
2,说说Object-C内存管理
OC内存管理分为MRC(手动引用计数),ARC(自动引用计数),遵循谁创建,谁释放,谁retain谁release原则;
-
MRC
需要程序员自己管理内存,使用alloc, copy, retain 使引用计数加一,对应的要使用release引用计数减一,或者autorealease 标记释放;
-
ARC
由系统自动管理内存,在合适的时间释放已经失去作用的内存空间.
-
引用计数
引用计数就是管理对象生命周期的的方式,当我们创建一个新对象的时候,它的引用计数为1,当有一个新的指针指向这个对象时,其引用计数加一,当某个指针不指向这个对象的时候,其引用计数减一,当对象的引用计数变为0时,说明对象不再被任何指针指向了,这时候就可以将对象销毁,回收内存;
3,属性的实质是什么?包括哪几个部分?属性默认的关键字有哪些?@dynamic关键字和@synthesize关键字是
做什么的?
-
属性的本质
属性的本质就是: 成员变量+存取方法 即:
ivar
+setter
+getter
-
属性关键字
strong
、assgin
、weak
、unsafe_unretaind
、nonatomic
、atomic
,readwrite
,readonly
,等等,各自作用不一一赘述
注意:循环引用中常使用weak
解决,IBOutlet
使用weak
,因为父空间在可视化操作时已经强引用了
assign
可用于非OC对象,而weak
必须用于OC对象,并且对象销毁时,会自动置为nil
-
@dynamic与@synthesize
使用@dynamic关键字,需要手动添加getter、setter方法,@synthesize自动生成setter、getter方法
4,说说代理,Block,通知
-
delegate
1,一对一的通讯交互,防止循环引用, 用
weak
,释放自动置为nil
.2,需要
@protocol
定义协议方法,指定代理,代理对象需要实现协议方法.3,更注重过程,类似
tableView
的代理方法,需要设置行数,设置cell
等,通讯较多推荐delegate
-
Block(闭包)
1,一对一的通讯交互,防止循环引用,用
copy
, 栈区拷贝到堆区.2,写法简洁,注重结果,如尾随闭包,回调结果,适用于通讯单一.
3,__block作用:将外部变量的传递形式由值传递,变为指针传递,从而可以获取并修改外部变量的值
-
NotificationCenter
1,一对多的通讯,通讯对象之间不需要建立关系,发送通知,注册通知,接收通知后,注意移除通知;
2,代码可读性差.
5,可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别
copy
返回的都是不可变对象(调用可变对象方法会crash),mutableCopy
返回的是可变对象只有对不可变的对象进行
copy
,是浅拷贝,其他情况都是深拷贝
-
浅拷贝
浅拷贝是指针拷贝,不生成新的指针地址
-
深拷贝
深拷贝是内容拷贝,开辟新内存,会生成行的指针地址,修改拷贝对象对原对象没有影响
-
copy 与 mutablecopy
不可变集合类(
NSArray
) 进行copy
是浅拷贝,指针复制, 进行mutableCopy
是深拷贝可变集合类(
NSMutableArray
) 进行copy
,mutableCopy
都是深拷贝
6,如何使自己写的对象具有拷贝功能
-
遵守
NSCopying
,NSMutableCopying
协议 -
实现协议方法
- (id)copyWithZone:(NSZone *)zone
- (id)mutableCopyWithZone:(nullable NSZone *)zone
7,Category,Extension,继承的作用,区别
- Category
不需要创建子类就能为现有类(系统类,自定义类)添加新方法;
-
作用
1,可以将类的实现分散到多个不同的文件中.
2,创建对私有方法的向前引用(类别中的声明方法未实现,编译器不会产生警告)
3,向对象添加非正式协议
-
局限
1,类别中只能添加方法,不能添加属性,(可以通过runtime添加)
2,方法名冲突,类别中方法名,与原始类方法名相同时,类别具有更高的优先级,先调用类别方法,覆盖原始类方法
- Extension
extension
是延展,匿名分类,一般用于声明私有属性,成员变量,私有方法.
-
与
Category
的区别1,
extension
可以添加属性,而Categary
不可以添加属性(可以通过runtime
添加)2,
extension
不能单独存在,必须寄生于类的.m
中,即:需要源码,而categary
可以单独存在,不需要源码.3,
extension
在编译器决议,它是类的一部分,而categary
,是在运行期决议. -
继承
继承是面向对象语言的特性,子类可以继承父类的属性与方法,如
BaseController
-
使用条件
1,当需要扩展的方法与原方法同名时,并且需要调用父类的同名方法,则需要继承。若此时使用分类,则分类的方法的实现 会覆盖原方法的实现,不会访问到原方法。
2,当需要扩展属性时。
8,Object-C的反射机制
OC的反射机制分为
Class
反射和SEL
反射
-
class反射
通过类名字符串获取类
Student *stu = [[NSClassFromString(@"Student") alloc]init]
将类名,转化成字符串
NSString *stuString = NSStringFromClass([Student class])
-
SEL反射
通过方法字符串,实例化方法
[stu performSelector:NSSelectorFromString(@"setName") withObject:nil]
将方法变成字符串
NSStringFromSelector(@selector*(setName:))
9,常见的系统单利类有哪些?如何实现完整的单利?
-
系统单利类
1,应用程序实例 [UIApplication sharedApplication]
2,消息中心 [NSNotificationCenter defaultCenter]
3,文件管理 [NSFileManager defaultManager]
4,应用程序设置 [NSUserDefaults standardUserDefaults]
5,应用程序cookies池 [NSHTTPCookieStorage sharedHTTPCookieStorage]
-
完整的单利类
实现了单例的初始化之后,一定要重写三个方法
+(id) allocWithZone:(struct _NSZone *)zone
-(id) copyWithZone:(NSZone *)zone
-(id) mutablecopyWithZone:(NSZone *)zone
10,NSTimer一定准确么?怎么解决
-
主线程
NSTimer
添加在主线程中,模式是NSDefaultRunLoopMode
, 主线程处理所有添加在主线程中的事件,例如UI界面的刷新,复杂的运算,等等,过多主线程事件的处理,导致线程阻塞;当滑动ScrollView
的时候,Runlop
会将Model
切换到TrackingRunLoopMode
,这时候的NSTimer
事件就不会回调,所以不准解决:将
NSTimer
添加到runloop
的特定NSRunLoopCommonModes
模式中[[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSRunLoopCommonModes];
-
子线程
子线程RunLoop默认关闭,需手动开启,否则定时器不准,
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run];
子线程定时器结束的时候,需要干掉,否则会造成资源的浪费
[_timer invalidate]; _timer = nil;