OC语言的一些面试题

1.@class的作用
@class一般用于头文件中通过前向声明,就可以声明了,但是在.m文件中还是需要使用#import进来的。它的作用只是前向声明。

2.#import和#include的区别?

import是Objective-C导入头文件的语法,可保证不会重复导入。

include是C/C++导入头文件的语法,如果是Objective-C与C/C++混编码,对于C/C++类型的文件,还是使用#include来引入,这种写法需要添加防重复导入的语法。

3.什么是单例,如何设计单例?
单例就是全局都只有一个对象存在,而且是在整个App运行过程中都存在。每个App都会有单例,比如UIApplication。而我们在做用户数据存储时,通常都会用单例存储,因为应用在所有操作中,经常要求先登录。

  • (instancetype)shared {
    static HYBUserManager *sg_userManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    if (sg_userManager == nil) {
    sg_userManager = [[HYBUserManager alloc] init];
    }
    });

    return sg_userManager;
    }

4.self.name=@object和name=@object有什么不同??
self.name =”object”:会调用对象的setName()方法;name = “object”:会直接把"object"字符串赋值给当前对象的name属性。

5.obj在编译时和运行时分别时什么类型的对象?
NSString *obj = [[NSData alloc] init];
在编译时,我们所声明的obj是NSString *类型,因此是NSString类型对象。在运行时,由于指针obj所指向的是NSData类型对象的内存,因此实际上是NSData类型的对象。在编译时,这一行代码会转换成类似这样:

NSString *obj = ((id (*)(id, SEL))objc_msgSend)([NSData class],@selector(alloc));

obj = ((id (*)(id, SEL))objc_msgSend)((id)obj, @selector(init));
由于在编译时,转换成id,因此可以用NSString *指向NSData对象,而id是具备运行时特性的,因此在链接时,通过id的isa指针可以找到其所属的类,因此最终类型还是通过isa确定其所属类型。

6.Objective-C的内存管理?
现在内存管理几乎都采用ARC,也就是Automatic Reference Counting,意思是自动引用计数。由编译器在编译时自动为添加retain、release等代码。
如果问的MRC,也就是Manual Reference Counting,意思是手动内存管理。
法则:谁使引用对象的引用计数+1,不再使用该对象时,谁就应该使该对象的引用计数-1

7.什么是MVC?
回答时会从项目的耦合度、团队开发如何减少冲突、如何降低团队与团队之间的沟通成本、如何将M、V、C之间按照既定的标准建立沟通的桥梁。
Model用于处理数据,通常来说,Model中会包含多个字段,用于存储数据。但是,Model还会有一部分逻辑,比如说:
@interface TestModel: HYBBaseModel
@property (nonatomic, assign) NSUInteger type;

// 这个不是接口返回的字段,但是由于type字段是一个数值,不是view需要显示的数据
// 所以我们最好将逻辑统一放到这里来,外部只管获取最终显示需要的值即可。即使哪天接口
// 返回的字段变化或者增加什么新的值,只需要处理这个模型内部就好了。
@property (nonatomic, copy, readonly) NSString relationship;
@end
对于View,不应该包含逻辑,应该根据模型直接获取数据。
对于Controller,大部分交互逻辑都集中到了这里,所有View需要的数据,都是通过Controller提取Model然后交给view去显示数据。

8.Push Notification 是如何工作的?
推送通知分为两种,一个是本地推送,一个是远程推送
本地推送:不需要联网也可以推送,是开发人员在APP内设定特定的时间来提醒用户干什么
远程推送:需要联网,用户的设备会于苹果APNS服务器形成一个长连接,用户设备会发送uuid和Bundle idenidentifier给苹果服务器,苹果服务器会加密生成一个deviceToken给用户设备,然后设备会将deviceToken发送给APP的服务器,服务器会将deviceToken存进他们的数据库,这时候如果有人发送消息给我,服务器端就会去查询我的deviceToken,然后将deviceToken和要发送的信息发送给苹果服务器,苹果服务器通过deviceToken找到我的设备并将消息推送到我的设备上,这里还有个情况是如果APP在线,那么APP服务器会于APP产生一个长连接,这时候APPF服务器会直接通过deviceToken将消息推送到设备上。

9.重写getter/setter方法?

@property (nonatomic, copy) NSString *blogName;
这里一旦连getter方法也重写,编译器不会给我们自动生成成员变量_blogName,因此我们需要在类的声明中添加一个成员变量_blogName:
@interface Demo () {
NSString *_blogName;
}

@end

在自动内存管理下(ARC):

  • (void)setBlogName:(NSString *)aName {
    if (_blogName != aName) {
    _blogName = nil;
    _blogName = [aName copy];
    }
    }

  • (NSString *)blogName {
    return _blogName;
    }

对于手动内存管理(MRC):

  • (void)setBlogName:(NSString *)aName {
    if (_blogName != aName) {
    [_blogName release];
    _blogName = nil;
    _blogName = [aName copy];
    }
    }

  • (NSString *)blogName {
    return _blogName;
    }

10.objective-c中的可变与不可变词典?
可变字典就是可以增、删、改操作的字典,对应于NSMutableDictionary类型。
不可变字典就是不能执行增、删、改操作的字典,对应于NSDictionary类型。

11.Category是什么,何时使用?
Category就是所谓的扩展。

有时我们需要在一个已经定义好的类中增加一些方法,而不想去重写该类,这时候使用扩展就很好。比如,当工程已经很大,代码量比较多,或者类中已经有很多方法,已经有其他代码调用了该类创建对象并使用该类的方法时,可以使用类别对该类扩充新的方法。

12.什么是Delegate?常用场景?
Delegate就是所谓的代理,代理是一种设计模式。在iOS开发中,会使用到大量的代理,而代理设计模式是苹果中的标准设置模式。

常用场景有反向传值。比如:苹果的蓝牙,我们进入到下一个界面去打开或者关闭蓝牙,当操作之后需要将状态反馈到前一个界面,并更新显示。对于这种状态,使用代理设计模式是很标准的模式

13.自动生成getter/setter方法?

  • (void)setName:(NSString *)aName;
  • (NSString *)name;

在后面有了property,直接使用@property (nonatomic, copy) NSString *name这样的方法来声明,编译器会自动生成getter/setter方法并生成一个_name成员变量。

14.id声明的对象有什么特性?
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};

typedef struct objc_object *id;

可其定义可知id类型是一个指向objc_object结构体类型的指针,这个结构体只有一个指向对象无类的指针isa,因此id可以指向任何类型的对象,故其具备运行时特性。

15.nil与NULL的区别?
nil和C语言的NULL相同,在objc/objc.h中定义。nil表示Objective-C对象的值为空。在C语言中,指针的空值用NULL表示。在Objective-C中,nil对象调用任何方法表示什么也不执行,也不会崩溃。

16.用NSLog函数输出一个浮点类型,结果四舍五入,并保留一位小数
float money = 1.011;
NSLog(@"%.1f", money);

17.Objective-C中有私有方法、私有变量么?
在类的.m实现文件内声明,就可以作为私有方法、私有变量。但是,并不是绝对的私有,如果外部知道有这么个方法,一样可以调用,而且不会报错。就像苹果公司没有公开出来的API,只要我们通过其它方式了解到api就可以调用。于是苹果审核时经常由于使用了私有api而打回来了。

18.property属性的修饰符有什么样的作用?
getter=getName、setter=setName:设置setter与getter的方法名
readwrite、readonly:设置可供访问级别
assign:方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题
retain:其setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序
copy:其setter方法进行copy操作,与retain处理流程一样,先对旧值release,再copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。
nonatomic:非原子性访问,不加同步, 多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。

19.简述tableview的重用机制?
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
这个方法就是重用机制的核心了。比如,有一个界面可显示10个cell,那么创建10次cell,并给cell指定同样的重用标识(当然,可以为不同显示类型的cell指定不同的标识)并且10个cell将全部都加入到visiableCells数组,reusableTableCells为空.
滚动tableView,当有一个cell完全移出屏幕时,这个cell就会被加入到reusableTableCells。而新出现的那个cell将加入到visiableCells,而这个cell就是被重用的。
如果要让tableview不重用,不设置reuseIdentifier就可以了。

20.viewDidLoad、loadView和viewDidUnload何时调用?
viewDidLoad在view加载完成时调用,loadView在controller的view为nil时调用。对于viewDidUnload现在已经不能直接调用了。

21.什么是 Runloop?
是一个与线程相关的机制,可以理解为一个循环,在这个循环里面等待事件然后处理事件.而这个循环是基于线程的,在Cocoa中每个线程都有它的runroop,通过他这样的机制,线程可以在没有事件要处理的时候休息,有事件运行,减轻CPU压力。

22.Toll-Free Bridging 是什么?什么情况下会使用?
Toll-Free Bridging用于在Foundation对象与Core Foundation对象之间交换数据,俗称桥接
在ARC环境下,Foundation对象转成 Core Foundation对象
使用__bridge桥接以后ARC会自动2个对象
使用__bridge_retained桥接需要手动释放Core Foundation对象
在ARC环境下, Core Foundation对象转成 Foundation对象
使用__bridge桥接,如果Core Foundation对象被释放,Foundation对象也同时不能使用了,需要手动管理Core Foundation对象
使用__bridge_transfer桥接,系统会自动管理2个对象.

23.当系统出现内存警告时会发生什么?

  1. 会将不在当前窗口上的view暂时移除
  2. 释放掉沙盒里temp里的缓存文件
  3. 如果用户放任内存警告,最终会导致软件强制被系统关闭

24.什么是 Protocol,Delegate 一般是怎么用的?
协议是一个方法签名的列表,在其中可以定义若干个方法,遵守该协议的类可以实现协议里的方法
delegate用法:成为一个类的代理,可以去实现协议里的方法

25.autorelease 对象在什么情况下会被释放?
分两种情况:手动干预释放和系统自动释放
手动干预释放:指定autoreleasepool,当前作用域大括号结束就立即释放
系统自动去释放:不手动指定autoreleasepool,Autorelease对象会在当前的 runloop 迭代结束时释放

kCFRunLoopEntry(1):第一次进入会自动创建一个autorelease
kCFRunLoopBeforeWaiting(32):进入休眠状态前会自动销毁一个autorelease,然后重新创建一个新的autorelease
kCFRunLoopExit(128):退出runloop时会自动销毁最后一个创建的autorelease

26.为什么 NotificationCenter 要 removeObserver? 如何实现自动 remove?
如果不移除的话,万一注册通知的类被销毁以后又发了通知,程序会崩溃.因为向野指针发送了消息
实现自动remove:通过自释放机制,通过动态属性将remove转移给第三者,解除耦合,达到自动实现remove

27.为什么 UIScrollView 的滚动会导致 NSTimer 失效?
定时器里面有个runoop mode,一般定时器是运行在defaultmode上但是如果滑动了这个页面,主线程runloop会转到UITrackingRunLoopMode中,这时候就不能处理定时器了,造成定时器失效,原因就是runroop mode选错了,解决办法有2个,一个是更改mode为NSRunLoopCommonModes(无论runloop运行在哪个mode,都能运行),还有种办法是切换到主线程来更新UI界面的刷新

28.为什么当 Core Animation 完成时,layer 又会恢复到原先的状态?
因为这些产生的动画只是假象,并没有对layer进行改变

29.有用过一些开源组件吧,能简单说几个么,大概说说它们的使用场景实现。
AFN:网络请求
FMDB:使用数据库
MJExtension: JSON与Model互转
SVProgressHUD:提示HUD
Masonry:自动布局
MJRefresh:下拉和上拉刷新

你可能感兴趣的:(OC语言的一些面试题)