原 iOS面试题收集
发表于2年前(2013-07-22 13:47) 阅读(369) | 评论(0) 4人收藏此文章, 我要收藏
赞0
听云性能监测产品App、Server、CDN免费试用,绑定账号送京东卡
1.ARC 是什么?
ARC 是 iOS 5 推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单 地说,就是代码中自动加入了 retain/release,原先需要手动添加的用来处理内存管 理的引用计数的代码可以自动地由编译器完成了。
该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单 地理解 ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成 实例的引用计数管理部分代码。有一点,ARC 并不是 GC,它只是一种代码静态分 析(Static Analyzer)工具。
2.单实例架构:只需要一个实例。
查找文件:
例如:NSFileManager *manager;
manager = [NSFileManager defaultManager];
defaultManager 可以为我们创建一个属于我们自己的 NSFileManger 对象。
NSString *home = [@"~" stringByExpandingTildeInPath];将~替换成当前用户的主 目录。
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:home];返回一个 NSDictionaryEnumerator,它是 NSEnumerator 的子类。每次在这个枚举器对象中 调用 nextObject 时,都会返回该目录中得一个文件的另一个路径。
3.自动释放池的销毁时间
在我们一直使用的 Foudation 库工具中,创建和销毁自动释放池的方法非常明确: NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
...
[pool release];
创建一个自动释放池时,该池自动成为活动的池。释放该池时,其保留计数器值归 0 ,然后该池被销毁。在销毁的过程中,该池释放其包含的所有对象。当使用 Application Kit 时,cocoa 定期自动为你创建和销毁自动释放池。通常是在程序处理 完当前事件以后执行这些操作。你可以使用任意多得自动释放对象,当不再使用它 们时,自动释放池将自动为你清理这些对象。
你可能已经在 xcode 自动生成代码中遇见过另一种销毁自动释放池中对象的方式:- drain 方法。该方法只是清空自动释放池而不是销毁它。并且只适用于 mac os x10.4 以上的版本。
4.自动释放池的工作过程
我们在任何时候向一个对象发送 autorelease 消息,该对象都会呗添加到这个自动释 放池中。被加入到自动释放池的对象的引用计数器值不会变化。当自动释放池被销 毁时(向自动释放池发送 release 消息,自动释放池的引用计数器值变为 0,调用自身 的 dealloc 函数),会调用自身的 dealloc 函数,会向池中得对象发送 release 消息。
5.响应者链是什么
响应者链是 Application Kit 事件处理架构的中心机制。它由一系列链接在一起的响
应者对象组成,事件或者动作消息可以沿着这些对象进行传递。如图 6-20 显示的那 样,如果一个响应者对象不能处理某个事件或动作-也就是说,它不响应那个消息 ,或者不认识那个事件,则将该消息重新发送给链中的下一个响应者。消息沿着响 应者链向上、向更高级别的对象传递,直到最终被处理(如果最终还是没有被处理 ,就会被抛弃)。
当 Application Kit 在应用程序中构造对象时,会为每个窗口建立响应者链。响应者 链中的基本对象是 NSWindow 对象及其视图层次。在视图层次中级别较低的视图将 比级别更高的视图优先获得处理事件或动作消息的机会。NSWindow 中保有一个第 一响应者的引用,它通常是当前窗口中处于选择状态的视图,窗口通常把响应消息 的机会首先给它。对于事件消息,响应者链通常以发生事件的窗口对应的 NSWindow 对象作为结束,虽然其它对象也可以作为下一个响应者被加入到 NSWindow 对象的后面。
7.timer 的间隔周期准吗?为什么?怎样实现一个精准的 timer?
NSTimer 可以精确到 50-100 毫秒.
NSTimer 不是绝对准确的,而且中间耗时或阻塞错过下一个点,那么下一个点就 pass
过去了
8.Difference between shallow copy and deep copy?
浅复制和深复制的区别? 答案:浅层复制:只复制指向对象的指针,而不复制引用对象本身。 深层复制:复制引用对象本身。
意思就是说我有个 A 对象,复制一份后得到 A_copy 对象后,对于浅复制来说,A 和 A_copy 指向的是同一个内存资源,复制的只不过是是一个指针,对象本身资源 还是只有一份,那如果我们对 A_copy 执行了修改操作,那么发现 A 引用的对象同样 被修改,这其实违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了 两份独立对象本身。
用网上一哥们通俗的话将就是: 浅复制好比你和你的影子,你完蛋,你的影子也完蛋 深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
9.Difference between categories and extensions?
类别和类扩展的区别。
答案:category 和 extensions 的不同在于后者可以添加属性。另外后者添加的方法
是必须要实现的。
extensions 可以认为是一个私有的 Category。
10.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 这个实例变量(iV ar),如 果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果 这个方法还是没有被实现的话,程序会抛出一个 NSUndefinedKeyException 异常错 误。
(cocoachina.com 注:Key-V alue Coding 查找方法的时候,不仅仅会查找 someKey 这个方法,还会查找 getsomeKey 这个方法,前面加一个 get,或者_someKey 以及 _getsomeKey 这几种形式。同时,查找实例变量的时候也会不仅仅查找 someKey 这 个变量,也会查找_someKey 这个变量是否存在。)
设计 valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey 方法从对 象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很 多好处,下面的两个例子说明了这样做的好处。“
来至 cocoa,这个说法应该挺有道理。
因为我们知道 button 却是存在一个 highlighted 实例变量.因此为何上面我们只是 add 一个相关的 keypath 就行了,
可以按照 kvc 查找的逻辑理解,就说的过去了。
11.Difference between frame and bounds?
frame 和 bounds 有什么不同?
答案:frame 指的是:该 view 在父 view 坐标系统中的位置和大小。(参照点是父亲
的坐标系统)
bounds 指的是:该 view 在本身坐标系统中 的位置和大小。(参照点是本身坐标系
12.方法调度 当向一个对象发送消息时(调用方法),这个方法是怎么被调用的呢?这就依赖于方法
高度程序,方法调度程序查找的方法如下:
在本类的方法中,找被调用的方法,如果找到了,就调用,如果找不到被沿着继承 路径去查找,从哪个类找到,就调用哪个类的方法,如果到最根上的类还是没有找 到,那编译就会出错。
13.继承与复合
在 Objective-C 中支持继承,但只是支持单一继承(有且只有一个父类有),如果想使 用多继承的特性,可以使用分类和协议技术。
继承是 is-a,复合是 has-a。复合是通过包含指向对象的指针实现的,严格意义上讲, 复合是针对于对象间来说,对于基本数据类型来说,它们被认为是对象的一部分。
14.装箱与拆箱
由于 NSArray,NSDirectory 等类不能直接存储基本数据类型,所以要想在 NSArray
\NSDirectory 中使用基本数据类型,就得使用装箱与拆箱。
在 Objective-C 中,可以使用 NSNumber 和 NSValue 来实现对数据类型的包装, NSNumber 可以实现对基本数据类型的包装,NSV alue 可以实现对任意类型数据的 包装。
将基本类型封装成对象叫装箱,从封装的对象中提取基本类型叫拆箱(取消装箱),其 它语言如 Java 原生支持装箱与拆箱,Ojbective-C 不支持自动装箱与拆箱,如果需 要得需要自己来实现装箱与拆箱。
15.便利初始化
当一个类需要根据不同的情况来初始化数据成员时,就需要便利初始化函数,与 init 初始化不同的是,便利初始化函数有参数,参数个数可以有 1 到N个,N是类数据 成员个数。
指定初始化函数:什么是指定初始化函数?在类中,某个初始化函数会被指定为指 定的初始化函数,确定指定初始化函数的规则是初始化函数中,参数最多的为指定 初始化函数,
其它未被指定为指定初始化函数的初始化函数要调用指定初始化函数来实现。对于 该类的子类也是一样,只要重写或者直接使用父类的指定初始化函数。上述文字有 些绕,来个例子吧
@interface A{
int x; int y; }
-(id) init;
-(id) initWithX:(int) xValue; -(id) initWithY:(int) yValue; -(id) initWithXY:(int) xValue
yVal:(int) yValue;
这里 initWithXY 被确定为指定初始化函数。 -(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super init]){ x = xValue;
y = yValue;
}
return self; }
-(id) init{
if (self = self initWithXY:10 yVal:20){
}
return self;
}
.......
@interface B: A{
int z;
}
-(jd) initWithXY......;
@implementation B
-(id) initWithXY:(int) xValue yVal:(int) yValue{
if (self = [super initWithXY:10 yVal=20]){
z= 40;
}
return self; }
@end
16.cocoa
cocoa 实际上是由 2 个不同的框架组成的:Foundation Kit 和 Application Kit。
Application Kit 包含了所有的用户接口对象和高级类。
17.NSRange
typedef struct _NSRange { unsigned int location; unsigned int length; }NSRange;
这个结构体用来表示相关事务的范围,通常是字符串里的字符范围或者数组里的元 素范围。
18.三种赋值方式
1.NSRange range;
range.location = 17;
range.length = 4;
2.C 语言的聚合结构赋值机制
NSRange range = {17, 4};
3.Cocoa 提供的一个快捷函数 NSMakeRange() NSRange range = NSMakeRange(17, 4);
使用 NSMakeRange()的好处是你可以在任何能够使用函数的地方使用它,例如在方 法调用中将其当成参数传递。
19.几何数据类型
1.NSPoint 代表笛卡儿平面中得一个点(x, y).
typedef struct _NSPoint { float x;
float y;
}NSPoint;
2.NSSize 用来存储长度和宽度 typedef struct NSSize {
float width;
float height;
}NSSize;
3.NSRect 矩形数据类型,它是由点和大小复合而成 typedef struct _NSRect {
NSPoint origin;
20.字符串 NSString stringWithFormat:就是一个工厂方法,它根据你提供的参数创建新对象。 length:长度
isEqualToString:比较字符串内容是否相同 compart:将接受对象和传递来的字符串逐个字符的进行比较。返回一个 enum 数据 NSCaseInsensitiveSearch:不区分大小写字符。 NSLiteralSearch:进行完全比较,区分大小写 NSNumericSearch:比较字符串的字符个数,而不是字符值。 -(NSRange)rangeOfString:(NSString *)aString;
返回的 range.start 为开始位置,range.length 为长度。
21.NSMutableString 可变字符串。 stringWithCapacity:创建一个新的 NSMutableString
字符串的大小并不仅限于所提供的容量,这个容量仅是个最优值。如果要创建一个 40mb 的字符串。
NSMutableString *str = [NSMutableString stringWithCapacity:42]; appendString 接受参数 aString,然后将其复制到接收对象的末尾。
appendFormat 与 stringWithFormat:类似,但它将格式化的字符串附加在接收字符 串的末尾,而不是创建新的字符串对象。
22.集合家族
1.NSArray:是一个 Cocoa 类,用来存储对象的有序列表。 两个限制:1.只能存储 objective-c 的对象,不能存储 C 语言中得基本数据类型。
2.也不能存储 nil。
23.NSNumber 包装(以对象形式实现)基本数据类型 装箱:将一个基本类型的数据包装成对象。 取消装箱:从对象中提取基本类型的数据。 objective-c 不支持自动装箱。
24.NSV alue 是 NSNumber 的父类。
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
传递的参数是你想要包装的数值的地址(如一个 NSSize 或你自己的 struct)。通常, 得到的是你想要存储的变量的地址(在 C 语言中使用操作符&)。你也可以提供一 个用来描述这个数据类型的字符串,通常用来说明 struct 中实体的类型和大小。你 不用自己写代码来生成这个字符串,@encode 编译器指令可以接受数据类型的名称 并为你生成合适的字符串。
NSRect rect = NSMakeRect(1, 2, 30, 40);
NSValue *value;
value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)]; [array addObject:value];
25.NSNull 只有一个方法[NSNull null];
[NSNull null]总是返回一样的数值,所以你可以使用运算符==将该值与其他值进行
比较
声明:OSCHINA 博客文章版权属于作者,受法律保护。未经作者同意不得转载。