一套稍微难点的iOS面试题 第2~12题参考答案
2.#import 跟#include 又什么区别 #import<> 跟 #import""又什么区别?
#import比起#include的好处就是不会引起交叉编译
在 Objective-C中,#import 被当成 #include 指令的改良版本来使用。除此之外,#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题
@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
@class就是告诉编译器有这么一个类,至于类的定义是啥不知道
@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
#import<> 跟 #import""又什么区别?
“”的意思是自己创建的文件,用这个首先会在当前的目录中寻找,如果找不到就到其他的位置寻找,“”和<>是相对的一个是自己创建的文件一个是系统的文件
3.类变量的@protected ,@private,@public,@package声明各有什么含义?
==========================
变量默认的级别是@protected,@public可见度最高,所有的类都能可见@ protected本类以及子类都可见,@ private只有本类的实例方法可见。
@package
@包是类似的。NET内部。这意味着该成员是只在定义它的框架访问。类似与Java的包的意思
4.id 声明的对象有什么特性?
id是任意对象类型的,不能表示基本对象类型,id类型是通用指针类型:因为通过指针,也就是内存地址来引用对象,所以可以自由地将它们在id变量之间来回赋值。因此返回id类型值的方法只是返回指向内存中某对象的指针。然后可以将该值赋给任何对象变量。因为无论在哪里,对象总是携带它的isa成员,所以即使将它存储在id类型的通用对象变量中,也总是可以确定它的类。
5.MVC是什么?有什么特性?为什么在iPhone上被广泛运用?
MVC设计模式考虑三种对象:模型对象、视图对象、和控制器对象。模型对象代表特别的知识和专业技能,它们负责保有应用程序的数据和定义操作数据的逻辑。视图对象知道如何显示应用程序的模型数据,而且可能允许用户对其进行编辑。控制器对象是应用程序的视图对象和模型对象之间的协调者。
6.对于语句NSString* testObject = [[NSData alloc] init];testObject 在编译时和运行时分别时什么类型的对象?
编译的时候时NSData 类型.运行时候 testObject 被强制转换为NSString.
7.什么是安全释放?
释放对象的时候将指针置为空.避免出现野指针,该释放的时候释放:释放前指针指向空,并且检查类型这个是安全释放的意思。8.为什么有些4.0独有的objective-c 函数在3.1上运行时会报错.而4.0独有的类在3.1上分配内存时不会报错?分配的结果是什么?
运行时因为 3.1的sdk 里没有对应的函数实现.所以会找不到对应的 @selector 指针. 错误.
而分配内存.应该是涉及到类的创建的机制上.(这个不懂.验证的话.可以 尝试 id testObject = [NSClassFromString(@"Null") alloc]; 然后在debugger里看结果);
9.为什么4.0独有的c函数在3.1的机器上运行不会报错(在没有调用的情况下?)而4.0独有的类名在3.1的机器上一运行就报错?
第一个问题不是很清楚,第二个参考上一题。
10.异常exception 怎么捕获?不同的CPU结构上开销怎样?C中又什么类似的方法?
下面是一个简单的异常捕获例子
@try { Statements } @catch (NSException *ex) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[ex name] message:[ex reason] delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alert show]; }
11.property中属性retain,copy,assgin的含义分别是什么?有什么区别?将其转换成get/set方法怎么做?有什么注意事项?
这个问题的答案网上大把,简单说一下。
assign:简单赋值,不更改索引计数(Reference Counting)。
copy:建立一个索引计数为1的对象,然后释放旧对象,其实这个是复制一个对象的副本,副本的计数器为一
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1,只是计数器加一,并且获得这个对象的所有权
使用assign:对基础数据类型(NSInteger,CGFloat)和C数据类型(int, float, double, char,等等)
使用copy:对NSString
使用retain:对其他NSObject和其子类
nonatomic关键字:
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
set方法如下:
// assign -(void)setMyObject:(id)newValue { _myObject = newValue; } // retain -(void)setMyObject:(id)newValue { if (_myObject != newValue) { [_myObject release]; _myObject = [newValue retain]; } } // copy -(void)setMyObject:(id)newValue { if (_myObject != newValue) { [_myObject release]; _myObject = [newValue copy]; } }
get方法如下
-(void)getMyObject { return _myObject ; }
这里顺便说一下为什么set方法要先release再赋值,举个简单的例子
如果我们retain的set方法这样写
-(void)setMyString:(NSString *)str { if (_myString != str) { _myString = [str retain]; } }
NSString对象会保留传入的字符串,使其retain计数+1.无论别处的代发如何处理该字符串,该对象会一直保留,直到被NSString对象释放为止。
那如果我们用这个存方法来给_myString对象赋值
NSString *string = [[NSString alloc] init]; [string setMyString:@"我的iPhone是白色的”]; // 然后你觉得不对,又这样 [string setMyString:@"我的iPhone是黑色的”];
执行这段代码之后,string会保留字符串“我的iPhone是白色的”,并将实例变量MyString指向该字符串。
接着,string会再保留字符串“我的iPhone是黑色的”,并将实例变量MyString指向新字符串。这就会导致一处泄露,
NSString对象丢掉了指向“我的iPhone是白色的”字符串的指针,但是却没有释放相应的所有权。
所以set方法需要完成的工作是保留新对象,释放当前拥有的对象,最后赋值。
12.委托是什么?委托的property声明用什么属性?为什么?
委托就是delegate,delegate就是声明方法,但是实现是让其他的类来实现,通常用来传参和数据。delegate通常是MVC实现的重要机制
在TableView的代码实现里.就用protocol 定义了Delegate和Datasource(都是delegate)应该提供的一些方法和参数传进来.property的声明属性通常用的是assgin。
所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系:
- 对象a创建并引用到了对象b.
- 对象b创建并引用到了对象c.
- 对象c创建并引用到了对象b.
这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中。
这种情况,必须打断循环引用,通过其他规则来维护引用关系。比如,我们常见的delegate往往是assign方式的属性而不是retain方式 的属性,赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的delegate又是a, 如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用delegate模式时,也要注意这点。
因为循环引用而产生的内存泄露也是Instrument无法发现的,所以要特别小心。
防止循环引用出现抱死的情况