个人面试题收藏
http://www.codingke.com/article/749
达内纪迎新老师博客
2016最全面试题
5、如何高效的对各种控件(label、button)进行切圆角、透明度、加边框(备注:不使用layer的方法)?
参考答案:
iOS 高效添加圆角效果实战讲解
6、多线程在实际现实中有哪些应用?(网络操作和大量图片处理不算)
参考答案:
通常耗时的操作都会放在子线程里处理,然后再回到主线程来显示。下面举几个例子:
我们要从数据库提取数据还要将数据分组后显示,那么就会开个子线程来处理,处理完成后才去刷新UI显示。
拍照后,会在子线程处理图片,完成后才回到主线程来显示图片。拍照出来的图片太大了,因此要做处理。
音频、视频处理会在子线程来操作
文件较大时,文件操作会在子线程中处理
做客户端与服务端数据同步时,会在后台闲时自动同步
7、如果app比较大,怎么样减少app的大小?
参考答案:
将build setting中的Optimization Level设置为Fastest, Smallest [-Os],在发布模式下,默认就是这样设置的
将build setting 中的Strip Debug Symbols During Copy设置为YES,在发布模式下,默认就是这样设置的
资源文件查找出所有未使用的,去掉这些永远不会使用的资源文件
对嵌入App的音频进行压缩处理
1、简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与alloc配对使用的方法是dealloc还是release,为什么?readwrite,readonly,assign,retain,copy,nonatomic 、atomic、strong、weak属性的作用?**
管理机制:使用了一种叫做引用计数的机制来管理内存中的对象。OC中每个对象都对应着他们自己的引用计数,引用计数可以理解为一个整数计数器,当使用alloc方法创建对象的时候,持有计数会自动设置为1。当你向一个对象发送retain消息 时,持有计数数值会增加1。相反,当你像一个对象发送release消息时,持有计数数值会减小1。当对象的持有计数变为0的时候,对象会释放自己所占用的内存。
retain(引用计数加1)->release(引用计数减1)
alloc(申请内存空间)->dealloc(释放内存空间)
readwrite: 表示既有getter,也有setter (默认)
readonly: 表示只有getter,没有setter
nonatomic:不考虑线程安全
atomic:线程操作安全 (默认)
线程安全情况下的setter和getter:
- (NSString) value {
@synchronized(self) {
return [[_value retain] autorelease];
}}
(void) setValue:(NSString)aValue {
@synchronized(self) {
[aValue retain];
[_value release];
_value = https://www.it610.com/article/aValue;
} }
retain: release旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
assign: 简单赋值,不更改索引计数 (默认)
copy: 其实是建立了一个相同的对象,地址不同(retain:指针拷贝 copy:内容拷贝)
strong:(ARC下的)和(MRC)retain一样 (默认)
weak:(ARC下的)和(MRC)assign一样, weak当指向的内存释放掉后自动nil化,防止野指针
unsafe_unretained 声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。autoreleasing 用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放。
3、线程是什么?进程是什么?二者有什么区别和联系?**
一个程序至少有一个进程,一个进程至少有一个线程:
进程:一个程序的一次运行,在执行过程中拥有独立的内存单元,而多个线程共享一块内存
线程:线程是指进程内的一个执行单元。
联系:线程是进程的基本组成单位
区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位 (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行 (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
举例说明:操作系统有多个软件在运行(QQ、office、音乐等),这些都是一个个进程,而每个进程里又有好多线程(比如QQ,你可以同时聊天,发送文件等)
4、谈谈你对多线程开发的理解?ios中有几种实现多线程的方法?**
好处:
1.使用线程可以把占据时间长的程序中的任务放到后台去处理
2.用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
3.程序的运行速度可能加快
4·在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。
缺点:
1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
2.更多的线程需要更多的内存空间。
3.线程的中止需要考虑其对程序运行的影响。
4.通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。
实现多线程的方法:
NSObject类方法
NSThread
NSOperation
GCD
5、线程同步和异步的区别?IOS中如何实现多线程的同步?**
异步:举个简单的例子 就是游戏,游戏会有图像和背景音乐
同步:是指一个线程要等待上一个线程执行完之后才开始执行当前的线程,上厕所
NSOperationQueue:maxcurrentcount
NSConditionLock
7、获取一台设备唯一标识的方法有哪些?**
(1)UDID
(2)UUID
(3)MAC Address
(4)OPEN UDID
(5)广告标识符
(6)Vindor标示符
12、什么是安全释放?**
置nil 再释放
13、写一个标准宏MIN,这个宏输入两个参数并返回较小的一个?
#define MIN(X,Y) ((X)>(Y)?(Y):(X))
扩展:在定义宏的时候需要注意哪些问题?
宏全部大写 写在#import 下 @interface上 结尾无分号
1.1 iOS有三种多线程编程的技术,分别是:
1.、NSThread
2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)
3、GCD 全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用)
这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
1.2 三种方式的有缺点介绍:
NSThread:
优点:NSThread 比其他两个轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
**Cocoa operation **
优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoa operation 相关的类是 NSOperation ,NSOperationQueue。NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。
GCD
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。现在的iOS系统都升级到10了,所以不用担心该技术不能使用。
- 封装
封装是对象和类概念的主要特性。它是隐藏内部实现,提供外部接口,可以看作是“包装”。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,
对不可信的进行信息隐藏。
封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,
以特定的访问权限来使用类的成员。
好处:可以隐藏内部实现细节。通过大量功能类封装,加快后期开发速度。
- 继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下
对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。在考虑使用继承时,有一点需要注意,
那就是两个类之间的关系应该是“属于”关系。
例如,Employee(雇员)是一个人,Manager(领导)也是一个人,因此这两个类都可以继承Person类。
但是 Leg(腿) 类却不能继承 Person 类,因为腿并不是一个人。
- 多态
多态性(polymorphism)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,
赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
不同对象以自己的方式响应相同的消息的能力叫做多态。
意思就是假设生物类(life)都用有一个相同的 方法-eat; 那人类属于生物,猪也属于生物,
都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。
也就是不同的对象以 自己的方式响应了相同的消息(响应了eat这个选择器)。
实现多态,有二种方式,覆盖,重载。
? 覆盖(override),是指子类重新定义父类的虚函数的做法。
? 重载(overload),是指允许存在多个同名函数,而这些函数的参数表不同
(或许参数个数不同,或许参数类型不同,或许两者都不同)。
** 这里注意:OC没有重载,因为OC只认函数名,不认参数类型。OC不允许存在多个同名函数。
它们的目的都是为了——代码重用。
而多态则是为了实现另一个目的——接口重用!
多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
在类层次中,子类只继承一个父类的数据结构和方法,则称为单重继承。
在类层次中,子类继承了多个父类的数据结构和方法,则称为多重继承。
- id声明的对象有什么特性?
可以作为返回值,也可以声明对象。
例如
- (id)initWithName:(NSString *)name;
id obj = [NSObject new];
- (instancetype)initWithName:(NSString *)name;
instancetype只能作为返回值。
- OC如何对内存管理的,说说你的看法和解决方法。
1. 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2. 手动内存计数MRC:遵循内存谁申请,谁添加。谁释放的原则。
3. 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain)
池子中所有的内存空间也被自动释放掉。 内存池的释放操作分为自动和手动。
自动释放受runloop机制影响。
- 你对@interface中的成员变量和@property声明的属性的理解。
@interface AA: NSObject{ NSString *_name; //成员变量}@property NSString *sex; //属性如上所示:属性拥有setter和getter方法 外加_sex成员变量。_name只是成员变量, 没有setter和getter方法。
- do while 和while do的区别?
while do是先判断while中的表达式的真假,再执行循环。do while先进行循环一次,再判断while中的表达式的真假。
- 【个人面试题收藏】类别的作用?继承和类别在实现中有何区别?
正常情况下不可以添加属性。但是实际应用中可以通过runtime机制添加属性。
类别主要有3个作用:
- 将类的实现分散到多个不同文件或多个不同框架中。降低耦合性。
- 重写主类方法
- 向类中添加协议,属性,方法。
- 重写父类方法
- 在父类基础上增加属性,方法,协议
- 什么是KVC和KVO?
KVC(Key-Value-Coding):键 - 值编码是一种通过字符串间接访问对象的方式。而不是通过调用setter方法或通过实例变量访问的机制。很多情况下可以简化程序代码。例如:@interface MeiLing:NSObject@property NSString *name; @property UILabel *label; @end对于name的赋值 可以使用 meiLing.name = @"笑玲"; 这是点语法。调用的是setName方法。KVC的写法是 [meiLing setValue:@"梦玲" forKey:@"name"]; 通过name字符串赋值。当然也可以跨层赋值,例如为label的text属性赋值点语法: meiLing.label.text = @"笑玲"; KVC: [meiLing setValue:@"梦玲" forKeyPath:@"label.text"]; KVO:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。 KVO 只能被 KVC触发, 包括使用setValue:forKey:方法 和 点语法。通过下方方法为属性添加KVO观察- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context; 当被观察的属性发生变化时,会自动触发下方方法- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- 设计模式是什么?你知道哪些设计模式,并简要叙述。
- 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。- 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。- 委托模式:代理+协议的组合。实现1对1的反相传值操作。- 工厂模式:通过一个类方法,批量的根据已有模板生产对象。- MVC模式:Model View Control, 把模型 视图 控制器 层进行解耦合编写。- MVVM模式:Model View ViewModel 把 模型 视图 业务逻辑 层进行解耦合编写。
- ViewController的didReceiveMemoryWarning是在什么时候调用的?默认的操作是什么?
当系统内存不足时,首先UIViewController的didReceiveMemoryWarining方法会被调用。
默认操作如果当前控制器不是window的根视图控制器,会自动将self.view释放。
- UDP和TCP的区别是什么?
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
31.ViewController生命周期
按照执行顺序排列- initWithCoder:通过nib文件初始化时触发- awakeFromNib:nib文件被加载的时候,会发送一个awakeFromNib的消息到nib文件中的每个对象- loadView:开始加载视图控制器自带的view- viewDidLoad:视图控制器的view被加载完成- viewWillAppear:视图控制器的view将要显示在window上- updateViewConstraints:视图控制器的view开始更新AutoLayout约束- viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置- viewDidLayoutSubviews:视图控制器的view已经更新视图的位置- viewDidAppear:视图控制器的view已经展现到window上- viewWillDisappear:视图控制器的view将要从window上消失- viewDidDisappear:视图控制器的view已经从window上消失
- 如何将产品进行多语言发布,开发?
国际化操作在Xcode中,Project里,找到Localization,点击+号,添加想要支持的语言通过新建Strings文件,把文件进行国际化处理。 通过键值对的形式,同一个key在不同的国际化文件中,对应不同的值。通过 NSLocalizedStringFromTable 等方法,通过key来自动根据iOS设备的当前语言,显示不同的字符串。 - TCP/IP建立连接的过程?
- 在TCP/IP 协议中,TCP协议提供可靠的连接服务,采用三次握手建立连接;
- 第一次握手:建立连接时,客户端发送连接请求到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:服务器收到客户端连接请求,向客户端发送允许连接应答,
此时服务器进入SYN_RECV状态; - 第三次握手:客户端收到服务器的允许连接应答,向服务器发送确认,客户端和服务器进入通信状态,
完成三次握手。
(所谓的三次握手,就是要有三次连接信息的发送、接收过程。
TCP连的建立需要进行三次连接信息的发送、接收。)
- 编程中,保存数据有哪几种方式?
- 数据:Sqlite。 操作方式分为原生的sqlite3,FMDB,Coredata
- 归档:Archive。 自定义类型需要注意遵循NSCoding协议
- Plist:就是数组或字典,写入文件后的表现形式。
- NSUserDefault:本质上就是Plist。
- 写文件
- 上传到服务器
确保某一个类只有一个实例,而且自行实例化并向整个系统提供整个实例。
2、优点
1、减少内存开支和系统性能开销;
2、避免对资源的多重占用;
3、优化和共享资源访问。
3、缺点
1、单例模式没有接口,扩展很困难;
2、单例模式与单一职责有冲突。
block与delegate的比较:
block 和 delegate 都可以通知外面。block 更轻型,使用更简单,能够直接访问上下文,这样类中不需要存储临时数据,使用 block 的代码通常会在同一个地方,这样读代码也连贯。delegate 更重一些,需要实现接口,它的方法分离开来,很多时候需要存储一些临时数据,另外相关的代码会被分离到各处,没有 block 好读。
应该优先使用 block。而有两个情况可以考虑 delegate。
1.有多个相关方法。假如每个方法都设置一个 block, 这样会更麻烦。而 delegate 让多个方法分成一组,只需要设置一次,就可以多次回调。当多于 3 个方法时就应该优先采用 delegate。
- 为了避免循环引用,也可以使用 delegate。使用 block 时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而 delegate 的方法是分离开的,并不会引用上下文,因此会更安全些。
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 一个小故事,我的思考。
- 一个人的碎碎念
- 猎杀IP
- 七年之痒之后
- 我从来不做坏事
- 喂,你结婚我给你随了个红包
- 异地恋中,逐渐适应一个人到底意味着什么()
- 开花店的前景怎么样()