一套稍微难点的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声明各有什么含义?

Objective-C 对存取权限的设定。也是变量的作用域。

protected —Methods defined in the class and any subclasses can directly access the instance variables that follow.This is the default case.

该类和所有的子类中的方法可以直接访问这样的变量,这是默认的。

private —Methods defined in the class can directly access the instance variables that follow, but subclasses cannot.

该类中的方法可以访问这样的变量,子类不可以。

public —Methods defined in the class and any other classes or modules can di- rectly access the instance variables that follow.

除了自己和子类中的方法外,也可以被其他类或者其他模块中的方法所访问。开放性最大。

package —For 64-bit images, the instance variable can be accessed anywhere within the image that implements the class.

对于64位图像,这样的成员变量可以在实现这个类的图像中随意访问。

 

==========================

变量默认的级别是@protected,@public可见度最高,所有的类都能可见@ protected本类以及子类都可见,@ private只有本类的实例方法可见。

@package

@包是类似的。NET内部。这意味着该成员是只在定义它的框架访问。类似与Java的包的意思

4.id 声明的对象有什么特性?

id是任意对象类型的,不能表示基本对象类型,id类型是通用指针类型:因为通过指针,也就是内存地址来引用对象,所以可以自由地将它们在id变量之间来回赋值。因此返回id类型值的方法只是返回指向内存中某对象的指针。然后可以将该值赋给任何对象变量。因为无论在哪里,对象总是携带它的isa成员,所以即使将它存储在id类型的通用对象变量中,也总是可以确定它的类。

5.MVC是什么?有什么特性?为什么在iPhone上被广泛运用?

MVC 是一种设计模式.将代码按照 Modal-View-Controller 的结构分开来。
从我实际运用上来看.一是提高代码的复用性.二是便于维护.三是在低内存可用的设备上.由于 modal和view的分离.便于节省内存开销.lazyloading(延迟加载)。

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无法发现的,所以要特别小心。

 防止循环引用出现抱死的情况

posted @ 2012-11-20 20:54  疯狂的萝卜  阅读(66)  评论(0编辑  收藏  举报