iOS面试题
- 1.写一个NSString类的实现
+ (id)initWithCString:(c*****t char *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
+ (id) stringWithCString: (c*****t char*)nullTerminatedCString
encoding: (NSStringEncoding)encoding
{
NSString *obj;
obj = [self allocWithZone: NSDefaultMallocZone()];
obj = [obj initWithCString: nullTerminatedCString encoding: encoding];
return AUTORELEASE(obj);
}
2static keyword的作用:
(1)函数体内 static 变量的作用范围为该函数体。不同于 auto 变量。该变量的内存仅仅被分配一次,
因此其值在下次调用时仍维持上次的值;
(2)在模块内的 static 全局变量能够被模块内所用函数訪问,但不能被模块外其他函数訪问;
(3)在模块内的 static 函数仅仅可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明
它的模块内。
(4)在类中的 static 成员变量属于整个类所拥有,对类的全部对象仅仅有一份拷贝。
(5)在类中的 static 成员函数属于整个类所拥有。这个函数不接收 this 指针。因而仅仅能訪问类的static 成员变量。
3线程与进程的差别和联系?
进程和线程都是由操作系统所体会的程序执行的基本单元,系统利用该基本单元实现系统对应用的并发性。
程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后。在保护模式下不会对其他进程产生影响,而线程仅仅是一个进程中的不同执行路径。线程有自己的堆栈和局部变量。但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同一时候进行而且又要共享某些变量的并发操作,仅仅能用线程,不能用进程。
4堆和栈的差别
管理方式:对于栈来讲,是由编译器自己主动管理,无需我们手工控制;对于堆来说。释放工作由程序猿控制。easy产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),假设申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。
这是由于系统是用链表来存储的空暇内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。
由此可见。堆获得的空间比較灵活,也比較大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续。从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题。由于栈是先进后出的队列,他们是如此的一一对应。以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的。没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完毕的,比方局部变量的分配。动态分配由alloca函数进行分配,可是栈的动态分配和堆是不同的。他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构。计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比較高。堆则是C/C++函数库提供的。它的机制是非常复杂的。
5什么是键-值,键路径是什么
模型的性质是通过一个简单的键(一般是个字符串)来指定的。视图和控制器通过键来查找对应的属性值。在一个给定的实体中。同一个属性的全部值具有同样的数据类型。
键-值编码技术用于进行这种查找—它是一种间接訪问对象属性的机制。
键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的
性质是由先前的性质决定的,接下来每一个键的值也是相对于其前面的性质。键路径使您能够以独立于模型
实现的方式指定相关对象的性质。通过键路径,您能够指定对象图中的一个随意深度的路径,使其指向相
关对象的特定属性。
6目标-动作机制
目标是动作消息的接收者。一个控件。或者更为常见的是它的单元,以插座变量(參见"插座变量"部分)
的形式保有其动作消息的目标。
动作是控件发送给目标的消息,或者从目标的角度看,它是目标为了响应动作而实现的方法。
程序须要某些机制来进行事件和指令的翻译。这个机制就是目标-动作机制。
7objc的内存管理
?
?
假设您通过分配和初始化(比方[[MyClass alloc] init])的方式来创建对象。您就拥
有这个对象,须要负责该对象的释放。
这个规则在使用NSObject的便利方法new 时也同样适用。
?
? 假设您拷贝一个对象。您也拥有拷贝得到的对象,须要负责该对象的释放。
?? 假设您保持一个对象,您就部分拥有这个对象,须要在不再使用时释放该对象。
反过来。
?? 假设您从其他对象那里接收到一个对象。则您不拥有该对象。也不应该释放它(这个规则有少数
的例外,在參考文档中有显式的说明)。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
8 自己主动释放池是什么,怎样工作
当您向一个对象发送一个autorelease消息时。Cocoa就会将该对象的一个引用放入到最新的自己主动释放池。
它仍然是个正当的对象,因此自己主动释放池定义的作用域内的其他对象能够向它发送消息。当程序执行到作用域结束的位置时。自己主动释放池就会被释放,池中的全部对象也就被释放。
1. ojc-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在開始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,假设此对象的计数变为了0, 就会被系统销毁.
2. NSAutoreleasePool 就是用来做引用计数的管理工作的,这个东西一般不用你管的.
3. autorelease和release没什么差别,仅仅是引用计数减一的时机不同而已,autorelease会在对象的使用真正结束的时候才做引用计数减一.
9类工厂方法是什么
类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中,返回被创建的对象,并
进行自己主动释放处理。
这些方法的形式是+ (type)className...(当中 className不包含不论什么前缀)。
工厂方法可能不仅仅为了方便使用。它们不但能够将分配和初始化合在一起。还能够为初始化过程提供对
象的分配信息。
类工厂方法的还有一个目的是使类(比方NSWorkspace)提供单件实例。虽然init...方法能够确认一
个类在每次程序执行过程仅仅存在一个实例,但它须要首先分配一个“生的”实例,然后还必须释放该实例。
工厂方法则能够避免为可能没实用的对象盲目分配内存。
10单件实例是什么
Foundation 和 Application Kit 框架中的一些类仅仅同意创建单件对象,即这些类在当前进程中的唯一实例。举例来说,NSFileManager 和NSWorkspace 类在使用时都是基于进程进行单件对象的实例化。当向这些类请求实例的时候。它们会向您传递单一实例的一个引用。假设该实例还不存在。则首先进行实例的分配和初始化。单件对象充当控制中心的角色,负责指引或协调类的各种服务。
假设类在概念上仅仅有一个实例(比方
NSWorkspace),就应该产生一个单件实例,而不是多个实例。假设将来某一天可能有多个实例,您可
以使用单件实例机制,而不是工厂方法或函数。
11动态绑定
—在执行时确定要调用的方法
动态绑定将调用方法的确定也推迟到执行时。在编译时,方法的调用并不和代码绑定在一起,仅仅有在消实发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术。您的代码每次执行都能够得到不同的结果。执行时因子负责确定消息的接收者和被调用的方法。
执行时的消息分发机制为动态绑定提供支持。
当您向一个动态类型确定了的对象发送消息时。执行环境系统会通过接收者的isa指针定位对象的类。并以此为起点确定被调用的方法,方法和消息是动态绑定的。而且。您不必在Objective-C 代码中做不论什么工作,就能够自己主动获取动态绑定的优点。您在每次发送消息时,
特别是当消息的接收者是动态类型已经确定的对象时。动态绑定就会例行而透明地发生。
12obj-c的优缺点
objc优点:
1) Cateogies
2) Posing
3) 动态识别
4) 指标计算
5)弹性讯息传递
6) 不是一个过度复杂的 C 衍生语言
7) Objective-C 与 C++ 可混合编程
缺点:
1) 不支援命名空间
2) 不支持运算符重载
3)不支持多重继承
4)使用动态执行时类型。全部的方法都是函数调用。所以非常多编译时优化方法都用不到。(如内联函数等),性能低劣。
13sprintf,strcpy,memcpy使用上有什么要注意的地方
strcpy是一个字符串拷贝的函数。它的函数原型为strcpy(char *dst, c*****t char *src);
将 src開始的一段字符串复制到dst開始的内存中去,结束的标志符号为'\0',由于拷贝的长度不是由我们自己控制的,所以这个字符串拷贝非常easy出错。
具备字符串拷贝功能的函数有memcpy,这是一个内存拷贝函数。它的函数原型为memcpy(char *dst, c*****t char* src, unsigned int len);
将长度为len的一段内存,从src复制到dst中去,这个函数的长度可控。可是会有内存叠加的问题。
sprintf是格式化函数。
将一段数据通过特定的格式。格式化到一个字符串缓冲区中去。sprintf格式化的函数的长度不可控,有可能格式化后的字符串会超出缓冲区的大小,造成溢出。
14答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functi***** that take an integer argument and return an integer
15.readwrite,readonly。assign,retain,copy。nonatomic属性的作用
@property是一个属性訪问声明,扩号内支持以下几个属性:
1。getter=getterName,setter=setterName,设置setter与getter的方法名
2。readwrite,readonly,设置可供訪问级别
2,assign。setter方法直接赋值,不进行不论什么retain操作,为了解决原类型与环循引用问题
3,retain。setter方法对參数进行release旧值再retain新值。全部实现都是这个顺序(CC上有相关资料)
4,copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1。这是为了降低对上下文的依赖而引入的机制。
copy是在你不希望a和b共享一块内存时会使用到。
a和b各自有自己的内存。
5,nonatomic。非原子性訪问,不加同步,多线程并发訪问会提高性能。注意,假设不加此属性,则默认是两个訪问方法都为原子型事务訪问。锁被加到所属对象实例级(我是这么理解的...)。
atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。
在多线程环境下,原子操作是必要的,否则有可能引起错 误的结果。加了atomic。setter函数会变成以下这样:
16什么时候用delegate,什么时候用Notification?答:delegate针对one-to-one关系。而且reciever能够返回值 给sender。notification 能够针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到 reciever的某个功能反馈值,notification用于通知多个object某个事件。
17什么是KVC和KVO?答:KVC(Key-Value-Coding)内部的实现:一个对象在调用setValue的时候。(1)首先依据方法名找到执行方法的时候所须要的环境參数。
(2)他会从自己isa指针结合环境參数。找到详细的方法实现的接口。(3)再直接查找得来的详细的方法实现。KVO(Key-Value- Observing):当观察者为一个对象的属性进行了注冊,被观察对象的isa指针被改动的时候。isa指针就会指向一个中间类,而不是真实的类。所以 isa指针事实上不须要指向实例对象真实的类。
所以我们的程序最好不要依赖于isa指针。在调用类的方法的时候,最好要明白对象实例的类名
18ViewController 的 loadView, viewDidLoad, viewDidUnload 各自是在什么时候调用的?在自己定义ViewController的时候这几个函数里面应该做什么工作?答: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 。
19
"NSMutableString *"这个数据类型则是代表"NSMutableString"对象本身。这两者是有差别的。
而NSString仅仅是对象的指针而已。
面向过程就是分析出解决这个问题所须要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就能够了。
面向对象是把构成问题事务分解成各个对象。建立对象的目的不是为了完毕一个步骤,而是为了描叙某个事物在整个解决这个问题的步骤中的行为。。
20类别的作用
类别主要有3个作用:
()将类的实现分散到多个不同文件或多个不同框架中。
()创建对私有方法的前向引用。
()向对象加入非正式协议。
类别的局限性
有双方面局限性:
()无法向类中加入新的实例变量,类别没有位置容纳实例变量。
()名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将全然代替初始方法从而无法再使用初始方法。
无法加入实例变量的局限能够使用字典对象解决
21keywordvolatile有什么含意?并给出三个不同的样例:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到
这个变量时必须每次都小心地又一次读取这个变量的值,而不是使用保存在寄存器里的备份。以下是volatile变量的几个样例:
• 并行设备的硬件寄存器(如:状态寄存器)
• 一个中断服务子程序中会訪问到的非自己主动变量(Non-automatic variables)
• 多线程应用中被几个任务共享的变量
• 一个參数既能够是const还能够是volatile吗?解释为什么。
• 一个指针能够是volatile 吗?解释为什么。
以下是答案:
• 是的。一个样例是仅仅读的状态寄存器。
它是volatile由于它可能被意想不到地改变。它是const由于程序不应该试图去改动它。
• 是的。虽然这并不非经常见。一个样例是当一个中服务子程序修该一个指向一个buffer的指针时。
22@synthesize 是系统自己主动生成getter和setter属性声明
@dynamic 是开发者自已提供对应的属性声明
@dynamic 意思是由开发者提供对应的代码:对于仅仅读属性须要提供 setter,对于读写属性须要提供 setter 和getter。@synthesize 意思是,除非开发者已经做了,否则由编译器生成对应的代码,以满足属性声明。
查阅了一些资料确定@dynamic的意思是告诉编译器,属性的获取与赋值方法由用户自己实现, 不自己主动生成。
Difference between shallow copy and deep copy?
浅复制和深复制的差别?
答案:浅层复制:仅仅复制指向对象的指针。而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的仅仅只是是是一个指针,对象本身资源
还是仅仅有一份,那假设我们对A_copy执行了改动操作,那么发现A引用的对象同样被改动,这事实上违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象本身。
用网上一哥们通俗的话将就是:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
What is advantage of categories?
What is difference between implementing a category and inheritance?
类别的作用?继承和类别在实现中有何差别?
答案:category 能够在不获悉,不改变原来代码的情况下往里面加入新的方法。仅仅能加入,不能删除改动。
而且假设类别和原来类中的方法产生名称冲突。则类别将覆盖原来的方法,由于类别具有更高的优先级。
类别主要有3个作用:
(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)向对象加入非正式协议。
继承能够添加,改动或者删除方法。而且能够添加属性。
.Difference between categories and extensions?
类别和类扩展的差别。
答案:category和extensions的不同在于 后者能够加入属性。另外后者加入的方法是必须要实现的。
extensions能够觉得是一个私有的Category。
.Difference between protocol in objective c and interfaces in java?
oc中的协议和java中的接口概念有何不同?
答案:OC中的代理有2层含义,官方定义为 formal和informal protocol。前者和Java接口一样。
informal protocol中的方法属于设计模式考虑范畴,不是必须实现的。可是假设有实现。就会改变类的属性。
事实上关于正式协议,类别和非正式协议我非常早前学习的时候大致看过,也写在了学习教程里
“非正式协议概念事实上就是类别的还有一种表达方式“这里有一些你可能希望实现的方法,你能够使用他们更好的完毕工作”。
这个意思是。这些是可选的。比方我门要一个更好的方法,我们就会申明一个这种类别去实现。
然后你在后期能够直接使用这些更好的方法。
这么看,总觉得类别这玩意儿有点像协议的可选协议。"
如今来看。事实上protocal已经開始对两者都统一和规范起来操作,由于资料中说“非正式协议使用interface修饰“,
如今我们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。
What are KVO and KVC?
答案:kvc:键 - 值编码是一种间接訪问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量訪问的机制。
非常多情况下能够简化程序代码。apple文档事实上给了一个非常好的样例。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
详细用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。
比方我自己定义的一个button
[cpp]
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
对于系统是依据keypath去取的到对应的值发生改变。理论上来说是和kvc机制的道理是一样的。
对于kvc机制怎样通过key寻找到value:
“当通过KVC调用对象时,比方:[self valueForKey:@”someKey”]时。程序会自己主动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 someKey 这种方法,假设没找到,会继续查找对象是否带有someKey这个实例变量(iVar)。假设还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这种方法。
假设这种方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。
(cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这种方法,还会查找getsomeKey这种方法,前面加一个get。或者_someKey以及_getsomeKey这几种形式。
同一时候。查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。
)
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在发生错误前。有最后的机会响应这个请求。这样做有非常多优点。以下的两个样例说明了这样做的优点。
“
来至cocoa,这个说法应该挺有道理。
由于我们知道button却是存在一个highlighted实例变量.因此为何上面我们仅仅是add一个相关的keypath即可了,
What is purpose of delegates?
代理的作用?
答案:代理的目的是改变或传递控制链。
同意一个类在某些特定时刻通知到其他类。而不须要获取到那些类的指针。能够降低框架复杂度。
另外一点,代理能够理解为java中的回调监听机制的一种相似。
What are mutable and immutable types in Objective C?
oc中可改动和不能够改动类型。
答案:可改动不可改动的集合类。
这个我个人简单理解就是可动态加入改动和不可动态加入改动一样。
比方NSArray和NSMutableArray。前者在初始化后的内存控件就是固定不可变的,后者能够加入等,能够动态申请新的内存空间
When we call objective c is runtime language what does it mean?
我们说的oc是动态执行时语言是什么意思?
答案:多态。主要是将数据类型的确定由编译时。推迟到了执行时。
这个问题事实上浅涉及到两个概念,执行时和多态。
简单来说,执行时机制使我们直到执行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应同样的消息的能力叫做多态。意思就是假设生物类(life)都用有一个同样的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后。实现各自的eat,可是调用是我们仅仅需调用各自的eat方法。
也就是不同的对象以自己的方式响应了同样的消息(响应了eat这个选择器)。
因此也能够说,执行时机制是多态的基础?~~~
what is difference between NSNotification and protocol?
通知和协议的不同之处?
答案:协议有控制链(has-a)的关系。通知没有。
首先我一開始也不太明白,什么叫控制链(专业术语了~)。可是简单分析下通知和代理的行为模式。我们大致能够有自己的理解
简单来说,通知的话。它能够一对多,一条消息能够发送给多个消息接受者。
代理按我们的理解。到不是直接说不能一对多,比方我们知道的明星经济代理人,非常多时候一个经济人负责好几个明星的事务。
仅仅是对于不同明星间,代理的事物对象都是不一样的,一一对应,不可能说明天要处理A明星要一个公布会,代理人发出处理公布会的消息后,别称B的
公布会了。
可是通知就不一样。他仅仅关心发出通知,而不关心多少接收到感兴趣要处理。
因此控制链(has-a从英语单词大致能够看出。单一拥有和可控制的对应关系。