1.苹果手机的各个尺寸?(虽然是很基础的,但是偶尔也会问到,如果答不出来,真的很尴尬哦)
苹果型号 | 设备分辨率 | 逻辑分辨率 |
---|---|---|
iPhone4 | 640*960 | 320*480 |
iPhone 5 | 640*1136 | 320*568 |
iphone6,7,8(s) | 750*1334 | 375*667 |
iphone6,7,8(s) plus | 1242* 2208 | 414*736 |
iphone X | 1125*2436 | 375*812 |
2.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?
1). readwrite 是可读可写特性,同时创建set方法和get方法。
2). readonly 是只读特性,只会生成getter方法,不会生成setter方法 ;不希望属性在类外改变;
3). assign 是赋值特性,setter方法将传入参数直接赋值给实例变量;仅设置变量时;
4). retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
5). copy 表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时;
6).nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic。
3.assgin和weak什么区别呢?
weak 只可以修饰对象。如果修饰基本数据类型。weak 不会产生野指针问题。因为weak修饰的对象释放后(引用计数器值为0),指针会自动被置nil,之后再向该对象发消息也不会崩溃。 weak是安全的。
assign 可修饰对象,和基本数据类型。assign 如果修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。修饰的对象释放后,指针不会自动被置空,此时向对象发消息会崩溃。
4.类别的作用?继承和类别在实现中有何区别?
答:category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有3个作用:
1).将类的实现分散到多个不同文件或多个不同框架中。
2).创建对私有方法的前向引用。
3).向对象添加非正式协议。
继承可以增加,修改或者删除方法,并且可以增加属性。
5.类别/分类(category)和类扩展(extension)的区别?
扩展:
1.扩展可以添加属性,可以声明实例变量(私有的)。可以添加方法。
使用场景:
能为某个类附加额外的属性,成员变量,方法声明
一般的类扩展写到.m文件中
一般的私有属性写到类扩展
1.可以增加实例变量(或者属性),只是该实例变量默认是@private类型的(使用范围只能在自身类,而不是子类或其他地方);
2.类扩展中声明的方法没被实现,编译器会警告,但是类别中的方法没被实现编译器是不会有任何警告的。这是因为类扩展是在编译阶段被添加到类中,而类别是在运行时添加到类中。
3.类扩展不能像类别那样拥有独立的实现部分(@implementation部分),也就是说,类扩展所声明的方法必须依托对应类的实现部分来实现。
4.定义在 .m 文件中的类扩展方法为私有的,定义在 .h 文件(头文件)中的类扩展方法为公有的。类扩展是在 .m 文件中声明私有方法的非常好的方式。
类别:
使用场景:
1)针对系统特定类,例如:NSString,NSArray,NSNumber等。
2)针对自定义类,对于大型而复杂的类,为提高可维护性,把相关的方法分组到多个单独的文件中。
类别中原则上只能增加方法,不能添加属性,不可以声明实例变量。(如果非要加属性就要用到runtime ,用它进行关联。)
-
通过runtime给分类(category)添加属性:
#import "Person.h"
@interface Person (Play)
@property (nonatomic,copy) NSString *name;
@end
#import "Person+Play.h"
#import <objc/runtime.h>
static NSString *nameKey = @"nameKey"; //定义一个key值
@implementation Person (Play)
//运行时实现setter方法
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//运行时实现getter方法
- (NSString *)name {
return objc_getAssociatedObject(self, &nameKey);
}
@end
6.static 关键字的作用?
- 修饰局部变量
让局部变量只初始化一次
局部变量在程序中只有一份内存
并不会改变局部变量的作用域,仅仅是改变了局部变量的生命周期(只到程序结束,这个局部变量才会销毁)
- 修饰全局变量
全局变量的作用域仅限于当前文件。
7.block中的循环引用是怎么造成的?
某个对象有一个copy或者strong成员变量或者属性,这时block内部直接引用了成员变量或者self,这样就产生了self持有block成员,block成员持有self,就会导致循环引用。因为self本身就是一个strong类型的变量。苹果官方的建议是:传进block之前,把self转换成weak automatic的变量,这样在block中就不会出现对self的强引用。如果在block执行完成之前,self被释放,weakSelf也会置为nil。weak类型相对比较安全,因为可以在释放后自动置为nil,不会引起野指针。
8.简述内存分区情况?
1).代码区:存放函数二进制代码
2).数据区:系统运行时申请内存并初始化,系统退出时由系统释放。存放全局变量、静态变量、常量
3).堆区:通过alloc等函数或new等操作符动态申请得到,需程序员手动申请和释放
4).栈区:函数模块内申请,函数结束时由系统自动释放。存放局部变量、函数参数
9.介绍一下观察者模式?
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
在IOS中典型的推模型实现方式为NSNotificationCenter和KVO。
NSNotificationCenter
9.png1)观察者Observer,通过NSNotificationCenter的addObserver:selector:name:object接口来注册对某一类型通知感兴趣。在注册时候一定要注意,NSNotificationCenter不会对观察者进行引用计数+1的操作,我们在程序中释放观察者的时候,一定要去报从center中将其注销了。
2)通知中心NSNotificationCenter,通知的枢纽。
3)被观察的对象,通过postNotificationName:object:userInfo:发送某一类型通知,广播改变。
4)通知对象NSNotification,当有通知来的时候,Center会调用观察者注册的接口来广播通知,同时传递存储着更改内容的NSNotification对象。
KVO
KVO(Key-Value Observer)即键值观察。是一种没有中心枢纽的观察者模式的实现方式。一个主题对象管理所有依赖于它的观察者对象,并且在自身状态发生改变的时候主动通知观察者对象。
1)注册观察者
[object addObserver:self forKeyPath:property options:NSKeyValueObservingOptionNew context:]。
2)更改主题对象属性的值,即触发发送更改的通知。
3)在制定的回调函数中,处理收到的更改通知。
4)注销观察者 [object removeObserver:self forKeyPath:property]。
10.在一个app中间有一个button,在你手触摸屏幕点击后,到这个button收到点击事件,中间发生了什么?
响应链大概有以下几个步骤:
1)设备将touch到的UITouch和UIEvent对象打包, 放到当前活动的Application的事件队列中;
2)单例的UIApplication会从事件队列中取出触摸事件并传递给单例UIWindow;
3)UIWindow使用hitTest:withEvent:方法查找touch操作的所在的视图view。
RunLoop这边我大概讲一下:
1.主线程的RunLoop被唤醒;
2.通知Observer,处理Timer和Source 0;
3.Springboard接受touch event之后转给App进程;
4.RunLoop处理Source 1,Source1 就会触发回调,并调用_UIApplicationHandleEventQueue() 进行应用内部的分发;
5.RunLoop处理完毕进入睡眠,此前会释放旧的autorelease pool并新建一个autorelease pool。
深挖请去深入理解RunLoop
11.简单介绍一下内存管理?
12.如何在block内如何修改block外部变量?
使用__block进行修改。
在block内如何修改block外部变量引发的思考
13.什么是沙盒模型?哪些操作是属于私有api范畴?
答:某个iphone工程进行文件操作有此工程对应的指定的位置,不能逾越。
iphone沙箱模型的有四个文件夹documents,tmp,app,Library,永久数据存储一般放documents文件夹,得到模拟器的路径的可使用NSHomeDirectory()方法。Nsuserdefaults保存的文件在tmp文件夹里。
14.alloc和new的区别?
[className new]基本等同于[[className alloc] init]. 区别只在于alloc分配内存的时候使用了zone,这个zone是个什么东东呢?它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度。
15.空指针与野指针的区别?
1.空指针
1.没有存储任何内存地址的指针就称为空指针(NULL指针)
2.空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0。
2.野指针
"野指针"不是NULL指针,是指向"垃圾"内存(不可用内存)的指针。野指针是非常危险的。
总结
1.利用野指针发消息是很危险的,会报错。也就是说,如果一个对象已经被回收了,就不要再去操作它,不要再尝试给它发消息。
2.利用空指针发消息是没有任何问题的,也就是说下面的代码是没有错误的。
16.堆和栈的区别?
栈区:由编译器自动分配释放,存放函数的参数值,局部变量值等;
堆区:一般由程序员分配释放(使用new/delete或malloc/free),若程序员不释放,程序结束时可能由OS回收;
栈里面存放的是非对象的基本数据类型(包括指针),堆内存存放着oc对象
17.#include,#import与@class的区别?
#include是C中用来引用文件的关键字;
#import是OC中用来引用文件关键字;
@class仅仅是告诉编译器有这么一个类, 具体这个类里有什么信息, 完全不知。
引入@class主要是用来解决引用死锁。如果两个类存在循环依赖关系,即A->B,B->A,如果用#import来相互包含,就会出现编译错误:
Expected specifier-qualifier-list before ‘A’或者Expected specifier-qualifier-list before ‘B’。
一般情况下,在 .h文件中,只需要知道类的名字就可以了,所以用@class,而在 .m文件中通常需要知道类的成员变量即方法,所以要用#import来将类文件导进来。
18. http和scoket通信的区别?
http是客户端用http协议进行请求,发送请求时候需要封装http请求头,并绑定请求的数据,服务器一般有web服务器配合(当然也非绝对)。 http请求方式为客户端主动发起请求,服务器才能给响应,一次请求完毕后则断开连接,以节省资源。服务器不能主动给客户端响应(除非采取http长连接 技术)。iphone主要使用类是NSUrlConnection。
scoket是客户端跟服务器直接使用socket“套接字”进行连接,并没有规定连接后断开,所以客户端和服务器可以保持连接通道,双方 都可以主动发送数据。一般在游戏开发或股票开发这种要求即时性很强并且保持发送数据量比较大的场合使用。主要使用类是CFSocketRef。
19. TCP和UDP的区别?
答: TCP全称是Transmission Control Protocol,中文名为传输控制协议,它可以提供可靠的、面向连接的网络数据传递服务。传输控制协议主要包含下列任务和功能:
- 确保IP数据报的成功传递。
- 对程序发送的大块数据进行分段和重组。
- 确保正确排序及按顺序传递分段的数据。
- 通过计算校验和,进行传输数据的完整性检查。
TCP提供的是面向连接的、可靠的数据流传输,而UDP提供的是非面向连接的、不可靠的数据流传输。
简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。
20.NSOprationQueue 与 GCD 的区别与选用?
21. 队列和栈有什么区别?
答:队列和栈是两种不同的数据容器。从”数据结构”的角度看,它们都是线性结构,即数据元素之间的关系相同。
队列是一种先进先出的数据结构,它在两端进行操作,一端进行入队列操作,一端进行出列队操作。
栈是一种先进后出的数据结构,它只能在栈顶进行操作,入栈和出栈都在栈顶操作。
22.block 实现原理?
Objective-C是对C语言的扩展,block的实现是基于指针和函数指针。Block是可以获取其他函数局部变量的匿名函数。它能够捕获它所在函数内部的变量的函数指针、匿名函数或者闭包。
cocoaTouch框架下动画效果的Block的调用
使用typed声明block
typedef void(^didFinishBlock) (NSObject *ob);
这就声明了一个didFinishBlock类型的block,
然后便可用
@property (nonatomic,copy) didFinishBlock finishBlock;
声明一个blokc对象,注意对象属性设置为copy,接到block 参数时,便会自动复制一份。
为什么系统的UIView的动画,不需要处理循环引用问题?
原理: UIView的调用的是类方法,当前控制器不可能强引用一个类 ,所以循环无法形成 --> 动画block不会造成循环引用的原因。
23.SDWebImage的实现原理?
24.代理的作用?
代理的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。
另外一点,代理可以理解为java中的回调监听机制的一种类似。
25.KVO和KVC的区别?
KVO:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
KVC:键 – 值编码,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
26. HTTP协议中,POST和GET的区别是什么?
1).GET 方法
GET 方法提交数据不安全,数据置于请求行,客户端地址栏可见;
GET 方法提交的数据大小有限
GET 方法不可以设置书签
GET使用URL或Cookie传参。
2).POST 方法
POST 方法提交数据安全,数据置于消息主体内,客户端不可见
POST 方法提交的数据大小没有限制
POST 方法可以设置书签
POST将数据放在BODY中
27. fmmpeg框架?
答: 音视频编解码框架,内部使用UDP协议针对流媒体开发,内部开辟了六个端口来接受流媒体数据,完成快速接受之目的。
28.视图的生命周期?
iOS程序执行顺序和UIViewController 的生命周期(整理)
29. 请简要说明viewDidLoad和viewDidUnload何时调用?
答:viewDidLoad在view从nib文件初始化时调用,loadView在controller的view为nil时调用。此方法在编程实现view时调用,view控制器默认会注册memory warning notification,当view controller的任何view没有用的时候,viewDidUnload会被调用,在这里实现将retain的view release,如果是retain的IBOutlet view 属性则不要在这里release,IBOutlet会负责release 。
30.tableView 的重用机制?
tableView的重用机制就是每次只创建屏幕显示区域内的cell,通过重用标识符identifier来标记cell, 当cell要从屏幕外移入屏幕内时, 系统会从重用池内找到相同标识符的cell, 然后拿来显示。
31.描述一下面向过程编程和面向对象编程的区别以及优缺点?
面向过程编程:以事件为中心的编程思想。就是分析出解决问题所需的步骤,然后用函数把这些步骤实现,并按顺序调用,实现整个程序的功能。
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展 。
面向对象编程:面向对象是一种以“对象”为中心的编程思想,把具体的数据和操作封装起来,来构造和实现整个软件的功能。面向对象包含三个基本特征:继承,多态,封装。
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 。
缺点:性能比面向过程低 。
备注:
1.多态就是父类指针指向子类指针。一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。
2.多态在继承中的使用:
1):父类指针可以接收子类对象(赋值兼容规则)
2):父类的指针指向不同的子类对象,调用相同的方法,效果不同
32. delegate,block的区别?
33. imageNamed和imageWithContentsOfFile/+imageWithData:(scale:)/-initWithContentsOfFile:/-initWithData:的区别?
1. +imageNamed:该方法使用系统缓存,适合表视图重复加载图像的情形。同时该API根据UIScreen的scale,自动查找包含对应高倍图后缀名(@2x)的文件,如果找到二倍图,则image.scale=2.0,对应逻辑size大小以point度量(pixel度量的一半);如果没找到设置默认image.scale=1.0,对应逻辑size大小同像素尺寸。因此,使用该方法,无需特意指定高倍图后缀。在实际运行时,系统如果发现当前设备是Retina屏(scale=2),会自动寻找"*@2x.png"命名格式的图片,加载针对Retina屏的图片素材,否则会失真。
2. +imageWithContentsOfFile/+imageWithData:(scale:)/-initWithContentsOfFile:/-initWithData:(scale:)
34.懒加载的时候,使用self调用属性造成崩溃。
错误写法
-(UIView *)bgView {
if (!self.bgView) {
self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.bgView.backgroundColor = [UIColor redColor];
}
return self.bgView;
}
正确写法
-(UIView *)bgView {
if (!_bgView) {
self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.bgView.backgroundColor = [UIColor redColor];
}
return _bgView;
}
为什么会崩溃?
因为:我们在调用if语句做判断时,如果用self去访问的话,此时会调用他的setter跟getter方法,本身自己还没初始化,是nil,但是getter返回的也是nil,那在判断时就会进入死循环,所以就会报这个错.
35.成员变量,实例变量和属性的区别?
@interface ViewController : UIViewController
{
int count; //成员变量
id data; //实例变量
NSString *name; //实例变量
}
@property (nonatomic, copy) NSString *address; //属性
@end
实例是针对 类而言的。 实例是指类的声明; 由此推理, 实例变量 :是指由类声明的对象。
严格来讲, 上图中的 int count
是一个成员变量。 而 NSString * name
是一个实例变量。 至于id data
应该属于实例变量。因为 id 是OC特有的类型。从本质上讲, id 等同于 (void *)。
36.@public,@private,@protected,@package的区别?
@public:在任何地方都能直接访问对象的成员变量;
@private:只能在当前类的对象方法中直接访问,如果子类要访问需要在父类中实现set和get方法,在子类中调用;
@protected:可以在当前类及其子类对象方法中直接访问(系统默认下是用它来修饰的);
@package:在同一个包下就可以直接访问,比如说在同一个框架。
37.if和switch的使用?
switch通过编译成一个分支表来达到优化的目的,是通过空间的代价来换取时间。if-else语句会对一个个条件按顺序进行查找,直到找到符合条件的"入口"。
大多数情况下switch比if-else运行的要快,但只有当数量条件很大时,才快得明显。当条件增加的时候,if-else性能负担增加的程度比switch明显得多。因此我们倾向于在条件数量比较少的情况下使用if-else,而在条件数量较大的时候使用switch。
经典面试题汇总
《招聘一个靠谱的iOS》面试题参考答案(上)
《招聘一个靠谱的iOS》面试题参考答案(下)
部分内容摘自于网络,如有侵权,可通过简书联系我,谢谢!
网友评论