1、栈与队列的区别
栈(Stack):限定只能在表尾(栈顶)进行删除和插入操作的线性表。我们把允许删除的一端称为栈顶,另一端称为栈低。不含任何元素的栈称为空栈。栈又称为(Last In First Out)的线性表。栈的插入操作,叫做进栈,栈的删除叫做出栈。
队列(Queue):是只允许在一端进行插入操作,在另一端进行删除操作的线性表。队列是一种特殊的线性表,允许插入的一端为表尾,允许删除的一端为表头。队列是先进先出。我们在队尾插入数据,在队头删除数据。
2、self.name = @"zhang san"; 与name = @"zhang san"有什么区别?
self.name调用set方法赋值,name = @"zhang san"是普通赋值
3、内存管理 在dealloc方法中用【xxx release】还是self.xxx = nil 好 ?
self.xxx = nil 好,会先release再置为nil,这样就更安全的释放对象,防止野指针,防止内存泄漏
4、#include与#import区别 #import与@class区别?
#include与#import区别: 效果是相同的,只是后者会确保头文件只会导入一次,不会引起交叉编译;
#import与@class区别:#import会包含这个类的所有信息,包括实体变量和方法,@class只是告诉编译器,其后面声明的名称是类的名称,至于这个类是如何定义的暂时不用考虑,后面会再告诉你。
5、JSON中{ }代表_____,[ ]代表_____,试将下面的JSON串用OC对象表示出来
{ "people": [
{ "firstName": "Brett","lastName":"McLaughlin", "email":"aaaa" },
{ "firstName": "Jason","lastName":"Hunter", "email": "bbbb"},
{ "firstName": "Elliotte","lastName":"Harold", "email": "cccc" }
],
“location”:”中华人民共和国”
}
JSON中{ }代表对象,数据结构为{key1:value1, key2:value2, key3:…… }
[ ]代表数组,与其他语言中的数组类似。
@interface People: NSObject
@property(nonatomic, copy) NSString* strFirstName;
@property(nonatomic, copy) NSString* strLastName;
@property(nonatomic, copy) NSString* strEmail;
@end
6、线程是什么?进程是什么?二者有什么区别和联系?
进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。
进程是资源分配的最小单位,线程是程序执行的最小单位
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
联系:线程是进程的基本组成单元。
区别:
(1)调度:进程作为拥有资源的基本单位,线程作为调度和分配的基本单位。
(2) 并发性:进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
(3) 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但线程可以访问隶属于自己进程的资源。
(4) 系统开销:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
7、字典的工作原理是什么?
字典通过使用- (void)setObject:(id)anObject forKey:(id)aKey;方法,用Hash表来实现key和value之间映射和存储的。
哈希概念:哈希表本质是一个数组,每一个元素称为一个箱子,而箱子里面的存放的是键值对。
哈希表(Hash Table)也叫做散列表,这是根据关键码(key vlaue)而直接进行访问的数据结构。换句话说,通过把关键码映射到表里面的一个位置来访问记录,用来加快查找的速度。映射的函数就叫做散列函数,存放记录的数组也叫做散列表。
给定表M(称为哈希表),存在函数f(key)(函数称为哈希函数),给定任意的key值,然后代入函数之后能得到包含改关键字的记录在表中的具体位置。
8、程序的生命周期?视图的生命周期?
1.程序的生命周期
Not running
未运行 ,程序未启动。Inactive
未激活 ,程序在前台运行,但没有接收到任何事件。在程序没有事件需要处理时停留在这个状态,相当于程序休眠。Active
激活,程序在前台运行而且接收到了事件,App接下来会处理这个事件。一个应用程序大部分时间都处于这个状态。Backgroud
后台,程序在后台而且能执行代码,大多数程序只能短暂停留这个状态,马上进入Suspended状态。Suspended
挂起,程序在后台不能执行代码。但程序不会被马上杀死,当系统内存不足时,在这个状态的程序占用的内存优先被回收。
-
程序启动
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
-
程序已经活跃
- (void)applicationDidBecomeActive:(UIApplication *)application
-
程序将要失去活跃(按HOME键,失去活跃进入后台)
- (void)applicationWillResignActive:(UIApplication *)application
-
程序进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application {
-
程序将要进入前台
- (void)applicationWillEnterForeground:(UIApplication *)application
-
程序已经活跃
- (void)applicationDidBecomeActive:(UIApplication *)application
-
程序将要杀死
- (void)applicationWillTerminate:(UIApplication *)application
2.视图的生命周期
- (void)viewDidLoad; 视图已经加载
- (void)viewWillAppear:(BOOL)animated; 视图将要出现
- (void)viewDidAppear:(BOOL)animated; 视图已经出现
- (void)viewWillDisappear:(BOOL)animated; 视图将要消失
- (void)viewDidDisappear:(BOOL)animated; 视图已经消失
- (void)dealloc; 视图销毁
9、深拷贝和浅拷贝的理解?
浅拷贝只是拷贝了指针,而并没有拷贝对象本身;深拷贝则是指针和对象本身都进行了拷贝。
对于不可变对象时,无论是copy还是mutableCopy。结果都是浅拷贝
对于可变对象时,copy和mutableCopy都是深拷贝。
在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。
如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。如果要遵循NSCopying协议,那么必须实现copyWithZone方法。如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。
10、什么是序列化和反序列化,可以用来做什么?如何实现OC中复杂对象的存储?
序列化就是把对象转化成字节序列的过程
反序列化就是把字节序列恢复成对象的过程
作用:可以将对象写到文件或者数据库中,可以在网络中传输,反序列化后可以读取。
必须遵守NSCoding协议,才可以对OC对象进行序列化存储
11、runLoop是什么?
RunLoop 是一个运行循环,就是一种事件监听循环。就好比是一个while循环,监听到事件就工作,没有就处于休眠状态。
介绍:它可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationRunLoopModel应用程序启动时会使用,启动完成后将不再使用;GSEventReceiveRunLoopMode这个是接受系统内部的Model,通常做不到。
还有UITrackingRunLoopMode、NSDefaultRunLoopMode、NSRunLoopCommonModes三种模式是我们通常用到的,下文中会详细讲解,其中NSRunLoopCommonModes是一个占位符,NSDefaultRunLoopMode和UITrackingRunLoopMode都会绑定这个占位符。
UITrackingRunLoopMode : (优先切换!!)这个模式就是当UI事件交互的时候Runloop切换到的模式!!!
场景:这一模式优先级最高,当UI事件交互的时候,都会优先切换到这一模式。
NSDefaultRunLoopMode :Runloop的默认模式!只要有事件就处理!
场景:默认模式,只要有事件就会自动切换到此模式。
NSRunLoopCommonModes :占位符!!(在默认下和UITrackingRunLoopMode下!)
场景:这个主要用在添加一个NSTimer到RunLoop中。是一个tag,本质上不是一个Mode,默认NSDefaultRunLoopMode和 NSTrackingRunLoopMode都绑定这个tag。基本作用:
1.保持程序的持续运行(这也是iOS程序为什么能一直不会死的原因)。
2.处理App中的各种事件(比如触摸事件、selector事件、定时器事件等)。
3.节省CPU资源,提高程序性能,有事件就唤醒,没有就休眠。
12、block和函数指针的区别?
第一个区别,函数指针是对一个函数地址的引用,这个函数在编译的时候就已经确定了。而block是一个函数对象,是在程序运行过程中产生的。在一个作用域中生成的block对象分配在栈(stack)上,和其他所有分配在栈上的对象一样,离开这个作用域,就不存在了。
Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。1. 函数指针只能指向预先定义好的函数代码块(可以是其他文件里面定义,通过函数参数动态传入的),函数地址是在编译链接时就已经确定好的。
2. Block本质是Objective-C对象,是NSObject的子类,可以接收消息。
3. 函数里面只能访问全局变量,而Block代码块不光能访问全局变量,还拥有当前栈内存和堆内存变量的可读性(当然通过__block访问指示符修饰的局部变量还可以在block代码块里面进行修改)。
4. 从内存的角度看,函数指针只不过是指向代码区的一段可执行代码,而block实际上是程序运行过程中在栈内存动态创建的对象,可以向其发送copy消息将block对象拷贝到堆内存,以延长其生命周期。
13、在KVO中,是怎么知道监听的对象发生了变化的?
KVO底层封装了KVC,KVC最重要的原理就是isa-swizzling ,我们在利用KVO的时候就传入了观察者对象,以及观察的属性。我们在底层就通过对象的方法名得到环境参数,isa结合环境参数直接得出方法接口(SEL),最后得到该方法的函数实现(IMP)。我们对应属性的变化就通过对应的settr方法来到IMP,就会消息转发,从动态子类转发给父类,同时会触发KVO的 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;方法拿到变化
14、简述OC的内存管理机制,与retain配对使用的是dealloc还是release,为什么?与alloc配对使用的是dealloc还是release,为什么?
OC管理机制:OC使用引用计数的机制来管理内存中的对象,每个对象都有一个与之对应的“引用计数器”,可以理解为一个整数计数器。
当调用这个对象的alloc、retain、new、copy方法之后引用计数器值自动在原来的基础上加1,当调用这个对象的release方法之后它的引用计数器值减1,
如果一个对象的引用计数器值为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象,释放这个对象所占有的内存空间。
retain配对release使用:retain引用计数加1,release引用计数减1;
alloc配对dealloc使用:alloc申请内存空间,dealloc释放内存空间;
15、当我们释放对象时,为什么需要调用[super dealloc]方法?
因为子类是继承自父类的,那么子类中有一些实例变量是继承自父类的,所有我们需要调用父类的方法,将父类所拥有的实例释放掉。
16、自动释放池是什么,如何工作的?
自动释放池是cocoa提供的帮助我们管理对象内存的一个工具。当我们向一个对象发送autorelease消息时,这个对象就自动加入到最新的自动释放池中,当自动释放池被销毁的时候,会自动向自动释放池中的所有对象发送一条release消息。也就是说我们不再需要手动向每一个对象发送release消息以释放对象,而是将其加入到自动释放池中最后统一释放。使用自动释放池也可以避免一些人为原因导致的内存泄漏。
17、代理delegate与通知Notification、block的使用区别?
delegate 与 block 一般用于两对象一对一的通信交互,
delegate 需要定义协议方法,代理对象实现协议方法,并且需要建立代理关系才可以实心通信。
block 比较简洁,不要定义繁琐的协议方法,但是如果通信事件比较多时,建议使用delegate方法,
notification,主要用于1对多的通信方式,通信对象之间不需要建立关系,但是通知的代码可读性差;
delegate运行成本低。block成本很高的。
block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除;delegate只是保存了一个对象指针,直接回调,没有额外消耗。相对C的函数指针,只多做了一个查表动作
18、什么是KVC 和KVO?它们之间的关系是什么?
KVC : 键值编码,是Key Value Coding 的简称,cocoa的标准组成部分,是一种可以直接通过字符串的名字(Key)来访问类属性的机制,而不是通过调用Setter方法、Getter方法进行访问。
KVC是一个用于间接访问对象属性的机制(只是通过字符串访问,而不是访问器方法去访问一个对象实例变量的机制),使用该机制不需要调用set或get方法和“->”方法访问成员变量,而是通过setValue:forKey: 和 valueForKey:方法进行成员变量的访问,将在内部查找名为_key或key的成员变量,如果找不到,就会报错。
KVC的使用环境:无论是property还是普通的全局属性变量,都可以使用KVC;
KVC优点:1.主要的好处就是减少代码量;2.没有property的变量(即:私有变量private)也能通过KVC进行设置。
KVC缺点:如果key只写错,编写的时候不会报错,但是运行的时候会报错;
KVO : 键值监听,是Key Value ObserVing 的简称,当指定对象的属性被修改之后,允许对象接收到通知的机制。
KVO:是一个对象能够观察另外一个对象的属性的值,并且能够发现值得变化。KVO适合一个任意类型的对象对另外的对象进行监听,当被监听的对象一旦发生改变,观察者马上做出反应。但是也只能对属性作出反应,而不会对方法或动作作出反应。
KVO优点:
1.能够提供一种简单的方法实现两个对象的同步;
2、能够对内部对象的状态改变作出响应,而且不需要改变内部对象的实现;
3.能够提供被观察者属性的最新值和之前的值;
4.使用key Path来观察属性,因此可以观察嵌套对象;
5.完成了对观察对象的抽象,因为不需要额外的代码来允许观察者被观察。
KVO缺点:
1.我们观察的属性必须使用strings定义,编译时不会出现警告;
2.对属性重构,将导致观察代码不可用;
3.复杂的 “if” 语句要求对象正在观察多个值,是因为所有的观察代码通过一个方法来指向;
4.当释放观察者的时候不需要移除观察者。
KVO 为观察者模式,
[被观察者 addObserver:观察者 forKeyPath:被观察的属性 options: 被观察的选项 context: 一般写nil];//被观察者通过这个方法来添加观察者,然后只要被观察者的keyPath值发生变化(注意:单纯的改变它的值并不会调用下面的方法,只有通过getter和setter来改变才会触发KVO),就会在观察者里调用方法:observeValueForKeyPath:options:context ;所以,观察着需要实现该方法对KVO发出的通知作出回应;
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{ 着这里,通过keyPath 区分不同的观察者,然后在进行后续的操作};
最后,调用dealloc方法,移除观察者
[观察者 removeObserver:被观察者 forKeyPath:被观察的属性 context:nil];
所以,总的来说,谁要进行监听谁就注册,然后对响应进行处理即可,这样使观察者与被观察者完全解耦,运用很灵活;但是,KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会补全,容易写错;
19、OC语言的优缺点?
一、oc语言的特性
OC做为一门面向对象语言,具有面向对象的语言特性,如封装、继承、多态。他具有静态语言的特性(如C++),又有动态语言的效率(动态绑定、动态加载等)。
OC的动态特性表现为了三个方面:动态类型、动态绑定、动态加载。之所以叫做动态,是因为必须到运行时(run time)才会做一些事情。
(1)动态类型
动态类型,说简单点就是id类型。动态类型是跟静态类型相对的。像内置的明确的基本类型都属于静态类型(int、NSString等)。静态类型在编译的时候就能被识别出来。所以,若程序发生了类型不对应,编译器就会发出警告。而动态类型就编译器编译的时候是不能被识别的,要等到运行时(run time),即程序运行的时候才会根据语境来识别。所以这里面就有两个概念要分清:编译时跟运行时。基本的动态特性在常规的Cocoa开发中非常常用,特别是动态类型和动态绑定。由于Cocoa程序大量地使用Protocol-Delegate的 设计模式,因此绝大部分的delegate指针类型必须是id,以满足运行时delegate的动态替代
(2)动态绑定
动态绑定(dynamic binding),让代码在运行时判断需要调用什么方法,而不是在编译时。与其他面向对象语言一样,方法调用和代码并没有在编译时连接在一起,而是在消息发送时才进行连接。运行时决定调用哪个方法。
(3)动态加载
根据需求加载所需要的资源,这点很容易理解,对于iOS开发来说,基本就是根据不同的机型做适配。最经典的例子就是在Retina设备上加载@2x 的图片,而在老一些的普通屏设备上加载原图。随着Retina iPad的推出,和之后可能的Retina Mac的出现,这个特性相信会被越来越多地使用。
oc 语言的优点:类目、动态识别、支持c语言、oc与c++可以混编
缺点:不支持命名空间、不支持运算符重载、不支持多重继承
多态(Polymorphism)OC中的多态则是不同对象对同一消息的不同响应方式,子类通过重写父类的方法来改变同一消息的实现,体现多态性。具体来说指的是允许父类的指针指向子类对象,成为一个更泛化、容纳度更高的父类对象,这样父对象就可以根据实际是哪种子类对象来调用父类同一个接口的不同子类实现。
20、@synthsize与@dynamic的区别?
@synthsize是系统自动生成getter和setter方法
@dynamic告诉编译器,属性的获取与赋值方法由用户自己实现,不自动生成