芒果iOS开发之史上最全的面试题汇总一

objective-c 常见面试题

1OC 语言的基本特点 

OC 语言是 C 语言的一个超集,只是在 C 的基础之上加上了面向对象(oop) 的特性; 

OC Java 语言相同都是单继承,这一点与 C++语言不同(多重继承);
OC 不支持命名空间机制,取而代之的是在类名之前添加前缀,以此来区分。 

2、以下命名正确的是 

(1)类 (PersonpersonObjectAndKeyspersonAndOther) (2)对象 (objectAndKeysPerson_person$dog) (3)实例变量 (_dog^agenameName、) 

3、数据类型和表达式 

(1) inta=5,b=2,c=2,result,result=a*b++-c; result的值和b 的值。 

答:result 的值为 8,b 的值为 3。根据运算符的优先级(乘法比加法的优先 级高),首先计算 a*b,因为 b++,“++”在后面。因此,先计算 a*b,其结果为 10,计算完成后 b 的结果++,因此 b 的结果为 3。最后与 c 相减,result 的结果 为8。 

(2)result = (b > a)? a++ : ((++c > a-b)? ++c : b++),求 result,a, b,c 的值,假设 abc 的值分别为 123。(右结合性;运算符号优 先级->结合性->顺序) 

答:运算符号相同,因此判断运算符号的结合性。即表达式为:result = (b > a)? a++ :(++c > a-b)? ++c : b++),然后我们判断表达是(b > a)是否为真。 因此,result 的结果为 1,abc 的值分别为 223。 

(3)int a = 5, b = 12, c = 3, result = 0, d = 5, e = 2,result = a -= b /= c += d %= e;求 result,abcde。 

答:运算符号相同,因此,判断该运算符号的结合性。赋值运算符号为右结合, 因此,表达式从右开始计算。d %= 2,分解为 d = d % e,d 值为 1;计算 c += d, 同理,c值为4。再计算b /= c,b值为3;再计算a -= b,a值为2。最后将a 值赋值给 result。因此,result 的结果为 2,abcde 的结果分别是 23412。(复合赋值运算符效率更高) 

(4)如果第三题中 d -5,求 result。 答:%(模运算符号)的符号取决与第一个数,因此,result 的值为-1,ab、 

cde 的值分别为-162-12
(
5)假设 abc 的值分别是 456。那么 result = a < b < c,求 result 是多少? 

答:result 值为 1。 (6)解释 id 类型 

答:任意类型对象。程序运行时决定才对象的类型。 (7)解释 nil,发送消息时,程序是否会出现异常。 

答:不会,在 OC 语言中可以 nil 发送消息,而程序不会抛出异常,其结果是 什么也不做。 

4、流程控制语句 

(1)switch 语句每一 case 都需要添加 break 语句吗?
答:switch 语句中的 break 语句不是必须的,此外,default 语句也不是必须 

添加的。如果在某一个条件中添加(case 语句之后)break 语句,即当条件满足 时,跳出 switch 语句。
(2)do while 语句和 while 语句的区别,并写出几个死循环。 

答:do while 语句至少执行一次循环体,而 while 语句括号中的表达式为真, 才执行循环体。 

while(1){ }for(;)
(3)switch 语句 if 语句区别与联系以及它的优势在哪里 


答:均表示条件的判断,switch 语句表达式只能处理是整型、字符型和枚举类 型,而选择流程语句则没有这样的限制。但 switch 语句比选择流程控制语句效 率更高。
(4)int number = 26,k = 1,求 k 的值 

do {
k *= number % 10; 

number /= 10;
} while
(number); 

答:do while 语句的特点是,循环体至少执行一次。程序执行到表达式 k*=number%10,已知 number 26,又已知算术运算符比赋值运算符好优先 级别高,因此先计算 number%10,其结果为 6;已知 k 1,因此,k 的结果为 6number/=10,number 的值 2while 语句判断表达式是否为真,此时,number 2。继续执行循环体,此时 numberk 的值分别为 26,2%10 的结果仍为 2,再与 k 相乘,其 k 的结果为 12。程序执行到循环体第二行 number/10,此 时 number 已为 10,因此,number 的结果为 0while 表达式内条件为假,循 环就此结束。因此,k 的值为 12。 

5、写出以下方法类型、方法名称和返回值类型 

(1)-(void)initWithName:(NSString *)name andAge:(int) age;
(
2)+(Person *)personName:(NSString)name; (3)-(void)setName:(NSString *)name setAge:(int)age setDelegate:(id)delegate

(4)-(NSString *)name;
(5)+ (Kingdom *)shareKingdom; (6)+ (Kingdom *)defaultKingdom; 

6、创建一个这样的 Person 类,用类目的形式给 Person 添加一组方法(方法任意)、并且若干私有方法以及在 Person 类中添加一个协议(手写代码) 

.h文件
#import @”Person.h” 

@protocol PersonDelegate @required
- (void)thisRequiredMethod;
@optional 

- (void)thisOptionalMethod; @end 

@interface Person : NSObject { @private 

NSString *_name; 

NSInteger _age; } 

-  (void)test;

-  (void)test1:(int)arg1;

-  (void)test1:(int)arg1 test2:(int)arg2; @end
@interface Person (Create)
- (id)initWithName:(NSString *)aName;
- (id)initWithName:(NSString *)aName age:(int)age; + (id)personBorn;
@end

  

.m文件 

@interface Person () - (void)private1;
- (void)private2; @end @implementation 

- (void)test {}
- (void)test1:(int)arg1 {}
- (void)test1:(int)arg1 test2:(int)arg2 {} - (void)private1 {}
- (void)private2 {} 

- (id)initWithName:(NSString *)aName { self = [super init]; 

if (self) {
}
return self; 

}
- (id)initWithName:(NSString *)aName age:(int)age { 

...... } 

+ (id)personBorn {
Person *person = [[Person alloc] init]; return [person autorelease]; 

} @end 

7、协议的基本概念和协议中方法默认为什么类型 

答:OC 中的协议是一个方法列表,且多少有点相关。它的特点是可以被任何 类使用(实现),但它并不是类(这里我们需要注意),自身不会实现这样方法, 

      

而是又其他人来实现。协议经常用来实现委托对象(委托设计模式)。 如果一个类采用了一个协议,那么它必须实现协议中必须需要实现的方法,在 协议中的方法默认是必须实现(@required),添加关键字@optional,表明一旦 

采用该协议,这些“可选”的方法是可以选择不实现的。

8#include #import 的区别、#import @class 的区别 

答:#include #import 其效果相同,都是查询类中定义的行为(方法)。只 是后者不会引起交叉编译,确保头文件只会被导入一次。@class 的表明,只定 义了类的名称,而具体类的行为是不知道的,一般用于.h 文件,因此,@class #import 编译效率更高。此外@class #import 的主要区别在于解决引用死锁 的问题。 

9@public@protected@private 它们的含义与作用 

( 1) @public: 答:对象的实例变量的作用域在任意地方都可以被访问 

( 2) @protected: 答:对象的实例变量作用域在本类和子类都可以被访问 

( 3) @private: 答:实例变量的作用域只能在本类(自身)中访问 

(4)通过指针运算符(->)能够访问到 private 方法吗?OC 语言中还提供 了哪些方式能直接和间接的访问对象的实例变量? 

答:不可以,可以通过合成存取器访问实例变量,也可自己定义 setter getter 方法访问实例变量,KVC(key value coding)——键值编码,间接的方式访问实 例变量。 


10、简述类目优点和缺点,如果覆盖本类或者父类的方 法,会出现什么问题? 

答:(1)优点:不需要通过增加子类而增加现有类的行为(方法),且类目中 的方法与原始类方法基本没有区别;通过类目可以将庞大一个类的方法进行划 分,从而便于代码的日后的维护、更新以及提高代码的阅读性。 

(2)缺点:无法向类目添加实例变量,如果需要添加实例变量,只能通过 定义子类的方式;类目中的方法与原始类以及父类方法相比具有更高级别的优先 级,如果覆盖父类的方法,可能导致 super 消息的断裂。因此,最好不要覆盖原 始类中的方法。 

11、简述内存管理基本原则 

答:(1)如果使用 alloccopy(mutableCopy)或者 retian 一个对象时,你就 有义务,向它发送一条 release 或者 autorelease 消息。其他方法创建的对象,不 需要由你来管理内存。 

(2)向一个对象发送一条 autorelease 消息,这个对象并不会立即销毁, 而是将这个对象放入了自动释放池,待池子释放时,它会向池中每一个对象发送 一条 release 消息,以此来释放对象。 

(3)向一个对象发送 release 消息,并不意味着这个对象被销毁了,而是 当这个对象的引用计数为 0 时,系统才会调用 dealloc 方法,释放该对象和对象 本身它所拥有的实例。 

12、在 objective c 中是否支持垃圾回收机制? 答:OC是支持垃圾回收机制的(Garbage collection简称GC),但是apple的 

移动终端中,是不支持 GC 的,Mac 桌面系统开发中是支持的。 13、什么是 ARC 技术?与 GC 是否相同? 

答:ARC Automatic Reference Counting 的简称,我们称之为自动引用计数, 

是在IOS 5之后推出的新技术,它与GC的机制是不同的。我们在编写代码时, 不需要向对象发送 release 或者 autorelease 方法,也不可以调用 delloc 方法, 编译器会在合适的位置自动给用户生成 release 消息(autorelease),ARC 的特 点是自动引用技术简化了内存管理的难度。 

14、什么是 retain count
答:每一个对象都默认有一个 retainCount 的属性,数值的多少表示现在有几 

个实例正在引用它。当它为 0 时,系统会自动调用 dealloc 方法,将内存回收。 15、写出@property (nonatomic ,retain) Person *person; 

@synthesize person 具体实现,并指出其中含义。 

非原子性事物 

-  (void)setPerson:(Person *)person {
if (_person != person){ [_person release]; _person = [person retain]; }
}

-  (Person *)person {
return _person; }
原子性事物
- (void)setPerson:(Person *)person {
@synchronized(self) {
if (_person != person)

[_person release]; _person = [person retain]; } 

} } 

- (Person *)person { 

@synchronized(self) { 

return _person; } 

16、深、浅复制的基本概念以及他们的区别,可以用图 来加以说明。 

17、堆和栈的区别 

答:(1)栈区(stack)由编译器自动分配释放 ,存放方法(函数)的参数值, 局部变量的值等。先进后出。 

(2)堆区(heap)一般由程序员分配释放, 若程序员不释放,程序结束 时由OS回收 。 

(3)全局区(静态区)(static),全局变量和静态变量的存储是放在一块 的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始 化的静态变量在相邻的另一块区域。程序结束后有系统释放。 

(4)文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。 (5)程序代码区—存放函数体的二进制代码。 

18、用户自定义了一个对象,如何实现拷贝(可变和不 可变拷贝) 

:必须实现 copying mutableCopying 协议,表示返回一个不可变和可变的 对象。否则,程序将会出现异常。
- (id)copyWithZone:(NSZone *)zone

Person *person = [[self Class] allocWithZone:zone]; person ->age = self.age;
person ->name = self.name;
return person; 

}
- (id)mutableCopyWithZone(NSZone *)zone; 

19、以下代码有问题吗?如果有,会出现什么问题 

- (void) setName:(NSString *)name { 

self.name = name; } 

答:引起重复调用(自己调用自己)。 

20、定义属性时,什么时候用 assignretaincopy 以及 它们的之间的区别 

答:(1)assign:普通赋值,一般常用于基本数据类型,常见委托设计模式, 以此来防止循环引用。(我们称之为弱引用,weak

(2)retain:保留计数,获得到了对象的所有权。引用计数在原有基础上 加1。 

(3)copy:一般认为,是在内存中重新开辟了一个新的内存空间,用来 

      

存储新的对象,和原来的对象是两个不同的地址,引用计数分别 1。但是当 copy 对象为不可变对象时,那么 copy 的作用相当于 retain。因为,这样可以节约内 存空间。 

21、解释以下关键字,staticselfsuper 用实例说明 

static: 静态全局变量,持久性作用、存储区域在静态区域,它的生命周期 和应用进行绑定。程序结束时,由系统自动回收。 

self:当前消息的接收者。 super:向父类发送消息。 

22、解释 self = [super init]方法 

答:容错处理,当父类初始化失败,会返回一个 nil,表示初始化失败。由于 继承的关系,子类是需要拥有父类的实例和行为的,因此,我们必须先初始化父 类,然后再初始化子类。 

23、当我们释放对象时,为什么需要调用[super dealloc] 方法? 

答:(1)因为,子类是继承自父类,那么子类中有一些实例变量(对象),是 继承子父类的,因此,我们需要调用父类方法,将父类所拥有的实例进行释放。 

(2)先将子类所拥有的实例进行释放,然后再释放父类的。 24objective-c 有私方法么?私有变量呢? 

答:是有的,我们称之为延展。私有变量也是有的(@private)。 25、以下每行代码执行后,person 对象的 retain count 分 

别是多少?
Person *person = [[Person alloc] init]; // 1 

                    

[person retain]; [person release]; [person release]; 

// 2 // 1 

// 0 

26、在某个方法中 self.name = _name name = _name 他 们有区别吗,为什么? 

答:是有区别的,前者是存在内存管理的,它会对_name 对象进行保留或者拷 贝操作,而后者是普通赋值。 

27、假设我们写了一个类的合成存取器,@property (nonatomic, copy) NSString *name;@synthesize name; 

(1)NSString *aName = [NSString stringWithFormat:@”a”];
person.name = aName
此时 name 的引用计数是几,为什么,这么做 

有什么好处?
答:它的引用技术是 2,相当于 retain 操作。 

(2)NSMutableString*aName = [NSMutableString stringWithFormat:@”a”]; 同上 

答:它的引用技术是 1,真正意义上的拷贝。 (3)返回这一个字符串的类型,是可变的吗?如果不是,为什么,我们 又如何做? 

答:不可变,因为合成存取器中用的 copy。如果,我们需要返回一个可变 的字符串时,那么必须自己实现 setter getter 方法。 

28、自动释放池是什么,如何工作 

答:自动释放池是 NSAutorelease 类的一个实例,当向一个对象发送 autorelease 消息时,该对象会自动入池,待池销毁时,将会向池中所有对象发 送一条 release 消息,释放对象。[pool release]; [pool drain]表示的是池本身 

                  

不会销毁,而是池子中的临时对象都被发送 release,从而将对象销毁。 29、为什么 delegate(代理)属性都是 assign 而不是 retain 

的? 答:防止循环引用,以至对象无法得到正确的释放。 

30iOS 开发中数据持久性,有哪几种。 答:文件写入、对象归档、sqlite3 数据库、coredata 

31、对象归档的基本概念,以及它的特点是什么? 

答:归档为对象的数据持久化提供了一种解决方法,它特点是给归档的对象进 行加密,增强了数据的安全性。此外,自定义类的对象归档必须实现 NSCoding 协议。 

32、什么是谓词?
答:cocoa 中提供了一个 NSPredicate 的类,该类主要用于指定过滤器的条件, 

每一个对象通过谓词进行筛选,判断条件是否匹配。
33、什么是 KVC KVO?以及它们之间的关系是什么 

答:(1)KVC(键值编码)是一种间接访问对象实例变量的机制,该机制可以 不通过存取方法就可以访问对象的实例变量。非对象类型的变量将被自动封装或 者解封成对象。此外,使用 KVC 能够简化代码。我们需要注意 KVC 有两个较为 明显的缺点,一旦使用 KVC 你的编译器无法检查出错误,即不会对设置的键、 键路径进行错误检查,且执行效率要低于(虽然效率已经很高,你已经感觉不到) 合成存取器方法和自定的 setter getter 方法。因为使用 KVC 键值编码,它必 须先解析字符串,然后在设置或者访问对象的实例变量。 

(2)KVO(键值观察)是一种能使得对象获取到其他对象属性变化的通知 

                            

机制。
(3)实现 KVO 键值观察模式,被观察的对象必须使用 KVC 键值编码来修 

改它的实例变量,这样才能被观察者观察到。因此,KVC KVO 的基础或者说 KVO 的实现是建立在 KVC 的基础之上的。 

34、在 objective c 中如何实现 KVO 

答:(1)注册观察者(这里我们需要注意,观察者和被观察者不会被保留也不 会被释放) 

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 

options:(NSKeyValueObservingOptions)options 

context:(void *)context; 

(2)接收变更通知
- (void)observeValueForKeyPath:(NSString *)keyPath 

ofObject:(id)object change:(NSDictionary *)change context:(void *)context; 

(3)移除对象的观察者身份
- (void)removeObserver:(NSObject *)observer 

forKeyPath:(NSString *)keyPath; 

35、当我们释放我们的对象时,为什么需要调用[super dealloc]方法,它的位置又是如何的呢? 

答:因为子类的某些实例是继承自父类的,因此需要调用[super dealloc]方法, 来释放父类拥有的实例,其实也就是子类本身的。一般来说我们优先释放子类拥 有的实例,最后释放父类所拥有的实例。 

                      

36、以下代码会出项问题吗?如果有,我们又该如何修 改? 

@property (nonatomic, copy) NSMutableString *name; @synthesize name = _name; 

self.name = [NSMutableString stringWithFormat:@"..xyz"]; [self.name insertString:@"abc" atIndex:0]; 

答:不可变字符串不可以被修改,可以通过自定义 set 方法,将字符串的拷贝 改为可变的拷贝。 

37、当我们将一个对象加入自动释放池时,该对象何时 被销毁 

答:我们在 application kit 应用程序中,自动释放池中的临时对象被销毁的时 间时,一个事件循环结束后。注意自动释放池没有被释放,而是被排空了,向池 发送了 drain 消息。 

38、当我们调用一个静态方法时,需要对对象进行 release 吗? 

答:不需要,静态方法(类方法)创建一个对象时,对象已被放入自动释放池。 在池被释放时,很有可能被销毁。 

39、什么叫键路径? 

答:在一个给定的实体中,同一个属性的所有值具有相同的数据类型。 键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对 象性质序列。第一个键的性质是由先前的性质决定的,接下来每个键的值也是相 

                  

对于其前面的性质。键路径使您可以以独立于模型实现的方式指定相关对象的性 质。通过键路径,您可以指定对象图中的一个任意深度的路径,使其指向相关对 象的特定属性。 

40、以下代码存在内存泄露吗?如果有,如何去修改 

self.object = [NSObject alloc] init]; self.object = [NSObject object] retain]; self.object = [NSObject object]; 

- (void)dealloc { 

self.object = nil; 

[super dealloc]; } 

41、循环引用是什么,如何解决这样的问题 

答:对象 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 两端产生不必要的循环引用。 

42isMemberOfClass isKindOfClass 联系与区别 

答:两者都能检测一个对象是否是某个类的成员, 两者之间的区别是: 

isKindOfClass 不但可以用来确定一个对象是否是一个类的成员,也可以用来确 定一个对象是否是派生自该类的类的成员 ,而 isMemberOfClass 做不到后一点。 

ClassA 派 生 自 NSObject 类 , ClassA *a = [ClassA alloc] init]; [a isKindOfClass:[NSObject class]] 可以检查出 a 是否是 NSObject 派生类 的成员,但 isMemberOfClass 做不到。 






你可能感兴趣的:(iOS面试题,ios开发面试题,ios开发,面试题,芒果iOS,最全面试题)