目前在公司做白领社交产品 “在一起”,工作也快一年下面对 iOS
相关面试做一份总结。
说实话目前iOS
开发真是太多很多情况下大家情况良莠不齐很难分辨。目前在广州快一年了,其实还是很开心的,因为这里有自己😍事物所在。
OC理解和特性
作为开发者我们都知道语言的特性包括:面对对象,面向过程。Objc
就是关于面对对象语言,也就包括面向对象的特点:封装、继承、多态。下面是对三者优点列表😉
- 封装:对于要处理的问题进行模块开发,好处有利于我们对于功能的拓展
- 继承:通过继承实现对父类方法的实现,也可以在子类中重写父类方法
- 多态:通过同名函数但是输入形式参数的种类,数目,类型不同实现具体函数功能不同(具体实现可以参照
C & C++
在编译后形式~想了解的可以自己查找)
Objc
的动态特性:动态类型、动态加载、动态绑定。其实前面我们在runtime
的理解过程中有所讲解。
(1)动态类型:在
iOS
中我们经常见到id
类型,id
类型指在Objc
中动态类型。在实际应用中我们一般使用静态类型,静态类型:固定和可预知性。静态类型是强类型,动态类型是弱类型。例如:我们经常见到的protrcol
委托协议就是采取@proerty(nonatomic, weak) id<protrcol> delegate
(2)动态加载:基于动态类型,在某个实例对象被确定后,其类型便被确定了,该对象对应的属性和响应消息也被完全确定。
(3)动态绑定:是我们在适配机型加载过程中,动态实现图片的实现。例如,在Retina
设备上加载@2x
的图片。
内存管理原则
iOS5.0
之前:在iOS 5.0
之前Objc
内存管理试行谁创建,谁释放的原则。如果要对是初始化的类型进行alloc
,retain
,copy
,就需要手动进行release
进行释放。当计数为0时才会释放对应的初始化内存空间和指针,我们称为MRC
时代。iOS 5.0
之后:使用戏言iOS
开发那就是一个字:爽。在ARC
:自动计数模式开发程序,我们不用再手动释放申请的对象,程序开发过程终于见不到release
,autorelease
,retain
语句。不过我们这是就该注意到strong
和weak
的细微区别。
strong
&weak
区别
strong
:用来修饰强引用属性weak
:用来修饰弱引用属性
strong
& weak
实现具体情况
我们知道strong
的使用时强引用,使用强引用使我们在赋值时会使计数器 +1
;
释放时间:当指针指向新值或者指针不存在,指针不存在一般是在自动计数为0时指针会自动释放。weak
是弱引用,悲剧的是弱引用是不会再计数 +1
的。不过这也使我们在使用时很方便,因为我们如果要防止 block
中发生循环引用的时候,可以在 block
外使用_weak
进行修饰。
释放时间:对象的拥有者指向新值或者不存在时 weak
修饰的指针会自动置为 nil
。
weak
的实现原理:在每一个类中都有一个弱引用的列表,在释放时都会对列表进行访问。如果找到相应的对象就执行释放。
strong
:是通过 ARC
的自动计数来实现对于对象的释放。
在想一个对象发送 autorelease
消息时,其实目标不会立即释放,会有一个具体的时间值。在 autorelease
调用的时候,会对其中的对象挨个发送 release
语句对于每个对象进行相应的释放。后面会对于 autorelease
进行专项讲解,不过这里可以给大牛资料,下文
在 ARC
中我们不用手动向实例化对象发送 release
进行释放,但是在 MRC
中就需要我们对申请的对象进行手动释放对象。那么问题来啦,对象会立即释放吗?
记住一点在
MRC
也是对象有时也不会立即释放,需要当前对象的计数为0时才会使用dealloc
进行对象中所有的内容。
其他注意事项
- 当一个对象被
_strong
指向时,该对象是不会被释放的。但是当对象在超出其作用区域时(在C++
中局部变量在超出作用区域就会nil
),此时指针也会被置为nil
于此同时指针所指的内存空间也会被释放。
还有就是当试图控制器(View
Controller`)进行释放,其中的全局变量和局部变量都会被释放。也有意外就是实现循环引用,恭喜你好好修改下吧,因为这是个
BUG`。
局部变量:上面讲到的局部变量如果超出其范围就会置为nil
在方法中对象创建,为啦使内存能够尽可能的减少可以使用autoreleasepool
。使用方法:@autoreleasepool{}
;block
中为了避免循环引用就会使用_weak
进行修饰
ARC
不是万能的🔑:ARC
是基于在Foundation
之上进行的变量的管理,如果是CGtypeRef
类型就无法进行管理。例如:CGImageRef
的图片的信息
同样我们可以实现ARC
和非ARC
之间的进行混合编译,具体操作如下:在
ARC
中进行非ARC
程序的混合编译:-fno-fobjc-arc
;在非
ARC
中进行ARC
的混合编译:-fobjc-arc
;
不过目前我们使用ARC
较多,所以使用第一种的情形较多。swift
毕竟也发布两年之久,很多创业公司已经开始使用swift
拓展介绍
nonatomic
:原子操作,禁止多线程进行操作atomic
:原子操作,多线程安全是property
的默认操作基本类型assign
:表示设置器可以直接进行复制,基本用于基本数据类型(NSInteger
,CGFloat
)和C语言的基本数据类型(int
,float
,double
,char
)readwrite
:可以进行读写readonly
:进行只读copy
:在赋值过程中传入一份值得copy
,地址和内容都会重新赋值retain
:在赋值过程中会使用retain
对象,指向内容的指针会copy
设计模式
开发过程中我们都会使用到设计模式,这里就以两种设计模式进行举例:
MVC
设计模式
MVC
是一种架构模式,M
表示Model
,V
表示视图View
,C
表示控制器Controller
:
其实重要的还是需要自己动手亲自实现,这样可以锻炼自己的编码能力。
Model
负责存储、定义、操作数据;View
用来展示书给用户,和用户进行操作交互;Controller
是Model
和View
的协调者,Controller
把Model
中的数据拿过来给View
用。
Controller
可以直接与Model
和View
进行通信,而View
不能和Controller
直接通信。View
与Controller
通信需要利用代理协议的方式,当有数据更新时,Model
也要与Controller
进行通信,这个时候就要用Notification
和KVO
,这个方式就像一个广播一样,Model
发信号,Controller
设置监听接受信号,当有数据更新时就发信号给Controller
,Model
和View
不能直接进行通信,这样会违背MVC
设计模式。
MVVM
设计模式
这里关于 MVVM
的设计模式就不多说,因为目前还没有使用过。
Objc
中的协议
我们在 iOS
开发过程中我们经常会使用协议和代理模式来进行消息传递,协议一般是伴随着代理产生而产生。我们在实现协议的同时一般都会有代理形式进行完成。
协议中有两个属性:
@required
:是表明此中的方法一定要实现,在我们使用UITableViewDataSourceDelete
就有两个必须实现的方法@optional
:方法可以根据自己选着实现方法
在博客中有关于protrcol
的相关使用
Category
的优缺点
我们使用 Category
一般是在一个现有类中定向添加方法,其实我们使用常见的SDWebImage
本质就是一个类的类目:UIImageView
。
- 优点:
我们在一个现有类中可以增加方法,于此同时我们又不需要改变原来对象的属性。增加方法和原来方法使用是一样的
在多方法的使用过程中我们可以通过使用Category实现对类进行区分,达到方便管理类种方法的原则
- 缺点:
Category
允许我们对类进行添加特定方法,但是我们不能向类中添加成员变量。但是我们可以继承类在子类中进行相关成员属性添加
在增加方法的过程中,我们增加方法的优先级别比较高因此会覆盖父类中的方法。
例如:在界面我们相应手指触摸时有响应链,如果在子类中调用touch
方法没有调用父类就会使响应者连中断
键路径(keyPath
)、键值编码(KVC
)和键值观察(KVO
)
在我的博客中有所讲述,在这里就不赘述啦。不过这里给大家留一个问题?为什么使用KVC(Key-value-coding)
在效率不是很高?
NSNotification
、Block
、Delegate
和 KVO
的区别
博客中有详细介绍
Objective-C
中可修改和不可以修改类型
可修改和不可修改的集合类,我们在 iOS
开发过程中经常会遇到 NSArray
和 NSMutableArray
两种,两者的区别:
一个是可以动态添加,一个不可以动态添加
前者初始化后内存是固定不边的,后者经过初始化内存是可以发生改变的
这里我就引出一个概念:非容器对象和容器对象。
非容器对象:NSNumber
,NSSting
等只能放单个字符或者数字
容器对象:NSArray
,NSDictionary
等可以放置多个数据类型
但是在我们熟悉的 copy
过程中会发生哪些情况呢?
这里又提出另外的 copy
的新概念:copy
, mutableCopy
copy
:复制了一个imutable
的对象+ copyWithZone:
mutableCopy
:复制的是一个mutable
的对象,使用的方法+ mutableCopyWithZone:
下面我们给出在非容器对象复制后的具体情况
非容器对象 | 不变类(NSString) | 可变类(NSMustbleString) |
---|---|---|
copy | 浅Copy | 深Copy~返回的对象是不可变的对象 |
mutableCopy | 深Copy | 深Copy |
下面我们给出容器对象中复制的具体情况
容器类型 | 不变类型(NSArray) | 可变类型(NSMutableArray) |
---|---|---|
copy | 浅copy | 深copy |
mutableCopy | 深copy | 深copy |
但是在容器对象复制过程中我们需要记住一点,我们对于NSArray和NSMutable的copy是对于整体指针和内存来说。但是在容器内部每一个元素我们进行的都是指针copy,也就是我们所说的浅copy。
从上面列举的例子我们可以得出一个结论:
无论是非容器类型还是容器类型只有在不可变时(NSArray
,NSString
)使用copy
才是浅复制,也就是说只是复制指针而不复制内存。
在可变的类型(NSMutableString
, NSMutableArray
)在使用 copy
时会生成不可变类型。
具体为什么实现这种原理可以看下在 NSArray
和 NSMutable
实现接口,以及参照C++
的原理进行解释。
下面是参考资料:
当我们调用一个静态方法时,需要对对象进行 release
吗?
不要对静态方法进行释放,因为静态方法会放到自动释放池中,后面会自动释放。
我在博客中写过关于 Runtime
的解析,在那里我们可以看出一个类在解析过程中其中类中调用方法是Method形式,放在Struct
的Class
中的。执行过程AutoReleasePool
会进行管理。
大神文章写得很详细
当我们释放我们的对象时,为什么需要调用[super dealloc]
方法,它的位置又是如何的呢?
因为子类的某些实例是继承自父类的,因此需要调用[super dealloc]
方法, 来释放父类拥有的实例,其实也就是子类本身的。一般来说我们优先释放子类拥 有的实例,最后释放父类所拥有的实例。
static
、self
、super
关键字的作用
static
是在 C
和 C++
中经常使用的,在 Objc
中我们也是常常使用 static
来定义 cell
的 identifer
目前就想到这些。下面给出 static
的具体作用:
(1)
static
修饰的变量只是在第一次调用过程进行初始化,所以在第二次调用时会维持上一次的值
(2)在模块内我们使用的static
变量可以在模块中所有函数使用,但是在模块外就不可以进行访问
(3)在模块内的static
的函数只能被模块内的函数进行调用,不能被模块外的其他函数声明
(4)在类中的satic
的全局变量,在整个类中有且仅仅只有一份的copy
self
: 是我们在当前类消息的接受者super
: 是我们调用父类的方法,消息链过程中我们在touch
调用super
就是调用父类方法,防止消息链中断。
#include
与#import
的区别,#import
与 @class
的区别
#include
是我们在C/C++
经常使用到的引入到文件的方式#import
是我们在Objc
中使用引入头文件的方式,可以防止头文件被多次引用(如果头文件被多次应用,程序在编译过程中会把库函数编译到类中这样就占用较多内存)#import
和@class
两者之间的区别@class
是只是定义类名,对其中的行为并不知道,我们经常可以再很多类的.h
文件可以看到@class
由于仅仅是定义类的名字,所以在编译过程要比import
的效率高
此外@class
和#import
的主要区别在于解决引用死锁的问题
@public
、@protected
、@private
它们的含义与作用
@public
:对象的实例变量的作用域在任意地方都可以被访问@protected
:对象的实例变量作用域在本类和子类都可以被访问@private
:实例变量的作用域只能在本类(自身)中访问
解释 id
类型
任意类型对象,程序运行时才决定对象的类型。 这也是我们在上面解释的动态类型。
switch
语句 if
语句区别与联系
- 两者均是判断语句。但是
switch
只可以判断 整形,字符型,枚举类型; - 但是if并没有类型限制。
isMemberOfClass
和 isKindOfClass
联系与区别
两者都可以判断一个对象是否是某个类的成员
isKindOfClesss
不紧可以判断对象是否是一个类的成员,也可以判断一个对象是否派生于类的类成员
举例:如ClassA
派 生 自NSObject
类 ,ClassA *a = [ClassA alloc] init];
,[a isKindOfClass:[NSObject class]]
可以检查出a
是否是NSObject
派生类 的成员,但isMemberOfClass
做不到
iOS 开发中数据持久性有哪几种?
自动释放池工作原理
自动释放池的前世今生
Objective-C Autorelease Pool 的实现原理
参考资料:
AutoreleasePool大牛的资料
参考资料
详细内容参考地址
MVVM参考资料地址
MVVM升级到MVVMM
MVVM With ReactiveCocoa
Objective-C Category初体验
Objective-C相关Category的收集
参考路径
谈KVC、KVO(重点观察者模式)机制编程
iOS KVC & KVO
参考资料点击
copy与mutableCopy
NSArray与NSMutableArray的区别
深入理解RunLoop
详细参看