本文大部份内容源自:http://www.cnblogs.com/SharkBin/p/4618388.htmlhtml
有一部分是本身看到感受不错以后总结的:ios
本篇的面试题是我认为比较好的iOS开发基础知识点,但愿你们看过这后在理解的基础上掌握而不是死记硬背。死记硬背很快也会忘记的。c++
深拷贝同浅拷贝的区别:浅拷贝是指针拷贝,对一个对象进行浅拷贝,至关于对指向对象的指针进行复制,产生一个新的指向这个对象的指针,那么就是有两个指针指向同一个对象,这个对象销毁后两个指针都应该置空。深拷贝是对一个对象进行拷贝,至关于对对象进行复制,产生一个新的对象,那么就有两个指针分别指向两个对象。当一个对象改变或者被销毁后拷贝出来的新的对象不受影响。程序员
实现深拷贝须要实现NSCoying协议,实现- (id)copyWithZone:(NSZone *)zone 方法。当对一个property属性含有copy修饰符的时候,在进行赋值操做的时候实际上就是调用这个方法。面试
父类实现深拷贝以后,子类只要重写copyWithZone方法,在方法内部调用父类的copyWithZone方法,以后实现本身的属性的处理objective-c
父类没有实现深拷贝,子类除了须要对本身的属性进行处理,还要对父类的属性进行处理。算法
NSNotification是通知,也是一对多的使用场景。在某些状况下,KVO和NSNotification是同样的,都是状态变化以后告知对方。NSNotification的特色,就是须要被观察者先主动发出通知,而后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,可是其优势是监听不局限于属性的变化,还能够对多种多样的状态变化进行监听,监听范围广,使用也更灵活。编程
delegate 是代理,就是我不想作的事情交给别人作。好比狗须要吃饭,就经过delegate通知主人,主人就会给他作饭、盛饭、倒水,这些操做,这些狗都不须要关心,只须要调用delegate(代理人)就能够了,由其余类完成所须要的操做。因此delegate是一对一关系。swift
block是delegate的另外一种形式,是函数式编程的一种形式。使用场景跟delegate同样,相比delegate更灵活,并且代理的实现更直观。设计模式
KVO通常的使用场景是数据,需求是数据变化,好比股票价格变化,咱们通常使用KVO(观察者模式)。delegate通常的使用场景是行为,需求是须要别人帮我作一件事情,好比买卖股票,咱们通常使用delegate。
Notification通常是进行全局通知,好比利好消息一出,通知你们去买入。delegate是强关联,就是委托和代理双方互相知道,你委托别人买股票你就须要知道经纪人,经纪人也不要知道本身的顾客。Notification是弱关联,利好消息发出,你不须要知道是谁发的也能够作出相应的反应,同理发消息的人也不须要知道接收的人也能够正常发出消息。
dispatch_async(dispatch_get_main_queue(), ^{ //须要执行的方法 });
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主队列 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ //须要执行的方法 }]; [mainQueue addOperation:operation];
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil]; [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES]; [[NSThread mainThread] performSelector:@selector(method) withObject:nil];
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES]; -(void)timerMethod { //调用类方法 [[self class] staticMethod]; } -(void)invalid { [timer invalid]; timer = nil; }
typedef struct objc_object *id
id能够理解为指向对象的指针。全部oc的对象 id均可以指向,编译器不会作类型检查,id调用任何存在的方法都不会在编译阶段报错,固然若是这个id指向的对象没有这个方法,该崩溃仍是会崩溃的。
NSObject *指向的必须是NSObject的子类,调用的也只能是NSObjec里面的方法不然就要作强制类型转换。
不是全部的OC对象都是NSObject的子类,还有一些继承自NSProxy。NSObject *可指向的类型是id的子集。
封装、继承、多态
设计模式6个原则
设计一个类的功能,如何划分粒度(单一职责)
接口隔离。
若是有一个鸟类,有飞的动做,一个鸵鸟继承它是合适的吗(里氏替换)
类之间的依赖如何依赖偶合度最小(依赖倒转)
高层依赖低层,低层不能依赖高层。依赖接口,不能依赖具体的类。
若是A要调用C函数,但C是B的成员类,应该如何设计?(迪米特)
如何设计类,能作到只增长代码,而不修改代码,有哪些经验(开放封闭)
经过设计模式解决。
这些面试题都是 Objective-C基础面试题,一块儿来看看。
一、#import和#include的区别,@class表明什么?
@class通常用于头文件中须要声明该类的某个实例变量的时候用到,在m文件中仍是须要使用#import
而#import比起#include的好处就是不会引发重复包含
二、谈谈Object-C的内存管理方式及过程?
1.当你使用new,alloc和copy方法建立一个对象时,该对象的保留计数器值为1.当你再也不使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.
2.当你经过任何其余方法得到一个对象时,则假设该对象的保留计数器值为1,并且已经被设置为自动释放,你不须要执行任何操做来确保该对象被清理.若是你打算在一段时间内拥有该对象,则须要保留它并确保在操做完成时释放它.
3.若是你保留了某个对象,你须要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.
三、Object-C有私有方法吗?私有变量呢?
objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这彷佛就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 若是没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法
@interface Controller : NSObject { NSString *something; }
+ (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end
@private能够用来修饰私有变量
在Objective‐C中,全部实例变量默认都是私有的,全部实例方法默认都是公有的
四、Object-C有多继承吗?没有的话用什么代替?cocoa 中全部的类都是NSObject 的子类
多继承在这里是用protocol 委托代理 来实现的
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood的多态特性 在 obj-c 中经过委托来实现.
五、内存管理 Autorelease、retain、copy、assign的set方法和含义?
1,你初始化(alloc/init)的对象,你须要释放(release)它。例如:
NSMutableArray aArray = [[NSArray alloc] init]; 后,须要 [aArray release];
2,你retain或copy的,你须要释放它。例如:
[aArray retain] 后,须要 [aArray release];
3,被传递(assign)的对象,你须要斟酌的retain和release。例如:
obj2 = [[obj1 someMethod] autorelease];
对象2接收对象1的一个自动释放的值,或传递一个基本数据类型(NSInteger,NSString)时:你或但愿将对象2进行retain,以防止它在被使用以前就被自动释放掉。可是在retain后,必定要在适当的时候进行释放。
关于索引计数(Reference Counting)的问题
retain值 = 索引计数(Reference Counting)
NSArray对象会retain(retain值加一)任何数组中的对象。当NSArray被卸载(dealloc)的时候,全部数组中的对象会 被 执行一次释放(retain值减一)。不只仅是NSArray,任何收集类(Collection Classes)都执行相似操做。例如 NSDictionary,甚至UINavigationController。
Alloc/init创建的对象,索引计数为1。无需将其再次retain。
[NSArray array]和[NSDate date]等“方法”创建一个索引计数为1的对象,可是也是一个自动释放对象。因此是本地临时对象,那么无所谓了。若是是打算在全Class中使用的变量(iVar),则必须retain它。
缺省的类方法返回值都被执行了“自动释放”方法。(*如上中的NSArray)
在类中的卸载方法“dealloc”中,release全部未被平衡的NS对象。(*全部未被autorelease,而retain值为1的)
六、浅拷贝和深拷贝区别是什么
简单的来讲就是,在有指针的状况下,浅拷贝只是增长了一个指针指向已经存在的内存,而深拷贝就是增长一个指针而且申请一个新的内存,使这个增长的指针指向这个新的内存,采用深拷贝的状况下,释放内存的时候就不会出如今浅拷贝时重复释放同一内存的错误
七、C和obj-c 如何混用
1)obj-c的编译器处理后缀为m的文件时,能够识别obj-c和c的代码,处理mm文件能够识别obj-c,c,c++代码,但cpp文件必须只能用c/c++代码,并且cpp文件include的头文件中,也不能出现obj-c的代码,由于cpp只是cpp
2)在mm文件中混用cpp直接使用便可,因此obj-c混cpp不是问题
3)在cpp中混用obj-c其实就是使用obj-c编写的模块是咱们想要的。
若是模块以类实现,那么要按照cpp class的标准写类的定义,头文件中不能出现obj-c的东西,包括#import cocoa的。实现文件中,即类的实现代码中可使用obj-c的东西,能够import,只是后缀是mm。
若是模块以函数实现,那么头文件要按c的格式声明函数,实现文件中,c++函数内部能够用obj-c,但后缀仍是mm或m。
总结:只要cpp文件和cpp include的文件中不包含obj-c的东西就能够用了,cpp混用obj-c的关键是使用接口,而不能直接使用 实现代 码,实际上cpp混用的是obj-c编译后的o文件,这个东西实际上是无差异的,因此能够用。obj-c的编译器支持cpp
八、Objective-C中类别和类扩展的区别。
答案:category和extensions的不一样在于后者能够添加属性。另外后者添加的方法是必需要实现的。
extensions能够认为是一个私有的Category。
九、咱们说的Objective-C是动态运行时语言是什么意思?
答案:多态。 主要是将数据类型的肯定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。
简单来讲,运行时机制使咱们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不一样对象以本身的方式响应相同的消息的能力叫作多态。意思就是假设生物类(life)都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,可是调用是咱们只需调用各自的eat方法。
也就是不一样的对象以本身的方式响应了相同的消息(响应了eat这个选择器)。
所以也能够说,运行时机制是多态的基础?
十、Objective-C堆和栈的区别?
管理方式:对于栈来说,是由编译器自动管理,无需咱们手工控制;对于堆来讲,释放工做由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就肯定的常数),若是申请的空间超过栈的剩余空间时,将提示overflow。因 此,能从栈得到的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是因为系统是用链表来存储的空闲内存地址的,天然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。因而可知,堆得到的空间比较灵活,也比较大。
碎片问题:对于堆来说,频繁的new/delete势必会形成内存空间的不连续,从而形成大量的碎片,使程序效率下降。对于栈来说,则不会存在这个问题,由于栈是先进后出的队列,他们是如此的一一对应,以致于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,好比局部变量的分配。动态分配由alloca函数进行分配,可是栈的动态分配和堆是不一样的,他的动态分配是由编译器进行释放,无需咱们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。