2019面试题(上)

一.设计模式是什么? 你知道哪些设计模式,并简要叙述?

设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。设计模式

  1. MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
  2. MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
  3. 单例模式:经过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
  4. 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
  5. 委托模式:代理+协议的组合。实现1对1的反向传值操做。
  6. 工厂模式:经过一个类方法,批量的根据已有模板生产对象。

MVC 和 MVVM 的区别数组

在MVC下,Controller基本是没法测试的,里面混杂了个各类逻辑,并且分散在不一样的地方。有了MVVM咱们就能够测试里面的viewModel,来验证咱们的处理结果对不对(Xcode7的测试已经愈来愈完善了)。安全

好比iOS里面有iPhone版本和iPad版本,除了交互展现不同外,业务逻辑的model是一致的。这样,咱们就能够以很小的代价去开发另外一个app。bash

MVVM是MVC的一个升级版,目前的MVC也能够很快的转换到MVVM这个模式。VC能够省去一大部分展现逻辑。微信

缺点:网络

每一个VC都附带一个viewModel,类的数量*2多线程

咱们把逻辑给了viewModel,那势必Model也会变得很复杂,里面的属性和方法愈来愈多。可能重写的方法比较多,由于涉及到一些数据的转换以及和controller之间的通讯。app

因为数据都是从viewModel来,想一想忽然来了一个新人,一看代码,不知道真实的模型是谁。好比经常使用tableview的数据源,通常都是一个数组,若是不断的经过viewModel去取,沟通上没有那么直接。何况每封一层,意味着要写不少代码去融合他们的转换。oop

Model负责存储、定义、操做数据;性能

View用来展现给用户,而且和用户进行交互;

Controller是Model和View的协调者,Controller把Model中的数据拿过来给View使用。Controller能够直接与Model和View进行通讯,而View不能与Controller直接通讯。,当有数据更新时,Model也要与Controller进行通讯,这个时候就要用Notification和KVO,这个方式就像发广播同样,Model发信号,Controller设置接收监听信号,当有数据更新是就发信号给Controller,Model和View不能直接通讯,这样违背MVC设计原则。View与Controller通讯须要利用代理协议的方式,Controller能够直接根据Model决定View的展现。View若是接受响应事件则经过delegate,target-action,block等方式告诉Controller的状态变化。Controller进行业务的处理,而后再控制View的展现。

关于MVVM的优势:

  • 方便测试

  • 便于代码的移植

  • 兼容MVC

  • 类会增多

  • viewModel会愈来愈庞大

  • 调用复杂度增长

二.#import跟 #include 有什么区别,@class呢,#import<> 跟 #import””有什么区别?

(1)#import指令是Object-C针对@include的改进版本,能确保引用的文件只会被引用一次,不会陷入递归包含的问题中;

(2)@import与@class的区别:

#import会链入该头文件的所有信息,包括实体变量和方法等;二@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类如何定义的,暂时不用考虑。在头文件中,通常只须要知道被引用的类的名称就能够了,不须要知道其内部的实体变量和方法,因此在头文件中通常使用@class来声明这个名称是类的名称;而在实现类里面,由于会用到这个引用类的内部的实体变量和方法,因此须要使用#import类包含这个被引用类的头文件。

@class还能够解决循环包含的问题

(3)#import<>跟#import""的区别:

#import<>用来包含系统自带的文件,#import""用来包含自定义的文件

(4)属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么做用,在那种状况下用?

  • readwrite:是可读可写特性,同时生成get方法和set方法的声明和实现(补充:默认属性,将生成不带额外参数的getter和setter方法(setterff只有一个参数))
  • readonly:只读特性,只会生成get方法的声明和实现;不但愿属性在类外改变
  • assign:是赋值特性,set方法的实现是直接赋值,用于基本数据类型;仅设置变量时
  • retain:表示持有特性,set方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
  • copy:表示拷贝特性,set方法的实现是release旧值,copy新值,用于NSString、block等类型(set方法将传入的对象复制一份;须要彻底一份新的变量时使用);
  • nonatomic:非原子操做,决定编译器生成的setter getter是不是原子操做,atomic表示多线程安全,通常使用nonatomic

三.frame 和 bounds 有什么不一样?

frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统)

bounds指的是:该view在自己坐标系统中的位置和大小。(参照点是自己坐标系统)

四.Objective-C的类能够多重继承么?能够实现多个接口么?Category是什么?重写一个类的方式用继承好仍是分类好?为何?

答:Objective-C的类不能够多重继承;能够实现多个接口(协议);Category是类别;通常状况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其余类与原有类的关系。

五.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

@property 的本质是什么?

@property = ivar + getter + setter;“属性”

(property)有两大概念:ivar(实例变量)、getter+setter(存取方法)

“属性” (property)做为 Objective-C 的一项特性,主要的做用就在于封装对象中的数据。 Objective-C 对象一般会把其所须要的数据保存为各类实例变量。实例变量通常经过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。

六.@property中有哪些属性关键字?/ @property 后面能够有哪些修饰符?

属性能够拥有的特质分为四类:

  1. 原子性--- nonatomic 特质
  2. 读/写权限---readwrite(读写)、readonly (只读)
  3. 内存管理语义---assign、strong、 weak、unsafe_unretained、copy
  4. 方法名---getter= 、setter=
  5. 不经常使用的:nonnull,null_resettable,nullable

七.属性关键字 readwrite,readonly,assign,retain,copy,nonatomic 各是什么做用,在那种状况下用?

答:

  1. readwrite 是可读可写特性。须要生成getter方法和setter方法。
  2. readonly 是只读特性。只会生成getter方法,不会生成setter方法,不但愿属性在类外改变。
  3. assign 是赋值特性。setter方法将传入参数赋值给实例变量;仅设置变量时,assign用于基本数据类型。
  4. retain(MRC)/strong(ARC) 表示持有特性。setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1。
  5. copy 表示拷贝特性。setter方法将传入对象复制一份,须要彻底一份新的变量时。
  6. nonatomic 非原子操做。决定编译器生成的setter和getter方法是不是原子操做,atomic表示多线程安全,通常使用nonatomic,效率高。

八.什么状况使用 weak 关键字,相比 assign 有什么不一样?

  1. 在 ARC 中,在有可能出现循环引用的时候,每每要经过让其中一端使用 weak 来解决,好比: delegate 代理属性。
  2. 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性通常也使用 weak;固然,也可使用strong。

IBOutlet连出来的视图属性为何能够被设置成weak?

由于父控件的subViews数组已经对它有一个强引用。

不一样点:

assign 能够用非 OC 对象,而 weak 必须用于 OC 对象。

weak 代表该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。

九.怎么用 copy 关键字?

用途:

  1. NSString、NSArray、NSDictionary 等等常用copy关键字,是由于他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;

  2. block 也常用 copy 关键字。

说明:

block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 能够把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 仍是 strong 效果是同样的,但写上 copy 也无伤大雅,还能时刻提醒咱们:编译器自动对 block 进行了 copy 操做。若是不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操做”,他们有可能会在调用以前自行拷贝属性值。这种操做多余而低效。

十.用@property声明的 NSString / NSArray / NSDictionary 常用 copy 关键字,为何?若是改用strong关键字,可能形成什么问题?

答:用 @property 声明 NSString、NSArray、NSDictionary 常用 copy 关键字,是由于他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操做(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无心间变更,应该在设置新属性值时拷贝一份。

  1. 由于父类指针能够指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 不管给我传入是一个可变对象仍是不可对象,我自己持有的就是一个不可变的副本。
  2. 若是咱们使用是 strong ,那么这个属性就有可能指向一个可变对象,若是这个可变对象在外部被修改了,那么会影响该属性。

//总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无心间篡改不可变类型对象原来的值。

十一.浅拷贝和深拷贝的区别?

答:

浅拷贝:只复制指向对象的指针,而不复制引用对象自己。

深拷贝:复制引用对象自己。内存中存在了两份独立对象自己,当修改A时,A_copy不变。

十二.这个写法会出什么问题:@property (nonatomic, copy) NSMutableArray *arr;

问题:添加,删除,修改数组内的元素的时候,程序会由于找不到对应的方法而崩溃。

缘由:是由于 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。

十三.如何让本身的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

若想令本身所写的对象具备拷贝功能,则需实现 NSCopying 协议。若是自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。

具体步骤:

  1. 需声明该类听从 NSCopying 协议

  2. 实现 NSCopying 协议的方法。

十四.@synthesize 和 @dynamic 分别有什么做用?

@property有两个对应的词,一个是@synthesize(合成实例变量),一个是@dynamic。

若是@synthesize和@dynamic都没有写,那么默认的就是 @synthesize var = _var;

// 在类的实现代码里经过 @synthesize 语法能够来指定实例变量的名字。(@synthesize var = _newVar;)

  1. @synthesize 的语义是若是你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。

  2. @dynamic 告诉编译器,属性的setter与getter方法由用户本身实现,不自动生成(如,@dynamic var)。

十五.常见的 Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int

答:

Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,建立后即是对象,而C语言的基本数据类型int,只是必定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并非NSNumber的子类,固然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位仍是64位来决定是自己是int仍是long。

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

答:id 声明的对象具备运行时的特性,便可以指向任意类型的Objcetive-C的对象。

十七.Objective-C 如何对内存管理的,说说你的见解和解决方法?

答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。

  1. 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
  2. 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
  3. 内存释放池Release Pool:把须要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中全部的内存空间也被自动释放掉。内存池的释放操做分为自动和手动。自动释放受runloop机制影响。

十八.Objective-C 中建立线程的方法是什么?若是在主线程中执行代码,方法是什么?若是想延时执行代码、方法又是什么?

答:线程建立有三种方法:使用NSThread建立、使用GCD的dispatch、使用子类化的NSOperation,而后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,若是想延时执行代码能够用performSelector:onThread:withObject:waitUntilDone:

十九.Category(类别)、 Extension(扩展)和继承的区别

区别:

  1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。

  2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展能够扩展属性、成员变量和方法。

  3. 继承能够增长,修改或者删除方法,而且能够增长属性。

二十.咱们说的OC是动态运行时语言是什么意思?

答:主要是将数据类型的肯定由编译时,推迟到了运行时。简单来讲, 运行时机制使咱们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。

二十一.为何咱们常见的delegate属性都用是week而不是retain/strong?

答:是为了防止delegate两端产生没必要要的循环引用。

@property (nonatomic, weak) id delegate;

二十二。何时用delete,何时用Notification?

Delegate(委托模式):1对1的反向消息通知功能。

Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。可是并不关心谁想要知道这个。

二十三.什么是 KVO 和 KVC?

  1. KVC(Key-Value-Coding):键值编码 是一种经过字符串间接访问对象的方式(即给属性赋值)

    举例说明:

stu.name = @"张三" // 点语法给属性赋值 
    
    [stu setValue:@"张三" forKey:@"name"]; // 经过字符串使用KVC方式给属性赋值
    
    stu1.nameLabel.text = @"张三";
    
    [stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值
复制代码
  1. KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。

    KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。

// 经过下方方法为属性添加KVO观察
- (void)addObserver:(NSObject *)observer
                    forKeyPath:(NSString *)keyPath
                    options:(NSKeyValueObservingOptions)options
                    context:(nullable void *)context;
// 当被观察的属性发送变化时,会自动触发下方方法
- (void)observeValueForKeyPath:(NSString *)keyPath
                    ofObject:(id)object
                    change:(NSDictionary *)change
                    context:(void *)context{}

复制代码

KVC 和 KVO 的 keyPath 能够是属性、实例变量、成员变量。

二十四.KVC的底层实现?

当一个对象调用setValue方法时,方法内部会作如下操做:

  1. 检查是否存在相应的key的set方法,若是存在,就调用set方法。
  2. 若是set方法不存在,就会查找与key相同名称而且带下划线的成员变量,若是有,则直接给成员变量属性赋值。
  3. 若是没有找到_key,就会查找相同名称的属性key,若是有就直接赋值。
  4. 若是尚未找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。

这些方法的默认实现都是抛出异常,咱们能够根据须要重写它们。

二十五.ViewController生命周期

按照执行顺序排列:

  1. initWithCoder:经过nib文件初始化时触发。
  2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每一个对象。
  3. loadView:开始加载视图控制器自带的view。
  4. viewDidLoad:视图控制器的view被加载完成。
  5. viewWillAppear:视图控制器的view将要显示在window上。
  6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
  7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
  8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
  9. viewDidAppear:视图控制器的view已经展现到window上。
  10. viewWillDisappear:视图控制器的view将要从window上消失。
  11. viewDidDisappear:视图控制器的view已经从window上消失。

二十六.你是否接触过OC中的反射机制?简单聊一下概念和使用

  1. class反射

    经过类名的字符串形式实例化对象。

    Class class = NSClassFromString(@"student");
    Student *stu = [[class alloc] init];
    复制代码

    将类名变为字符串。

    Class class =[Student class];
    NSString *className = NSStringFromClass(class);
    复制代码
  2. SEL的反射

    经过方法的字符串形式实例化方法。

    SEL selector = NSSelectorFromString(@"setName"); 
    [stu performSelector:selector withObject:@"Mike"];
    复制代码

    将方法变成字符串。

    NSStringFromSelector(@selector*(setName:));
    复制代码

二十七.如何对iOS设备进行性能测试?

  1. app使用过程当中,接听电话。能够测试不一样的通话时间的长短,对于通话结束后,原先打开的app的响应,好比是否停留在原先界面,继续操做时的相应速度等。
  2. app使用过程当中,有推送消息时,对app的使用影响
  3. 设备在充电时,app的响应以及操做流畅度
  4. 设备在不一样电量时(低于10%,50%,95%),app的响应以及操做流畅度
  5. 意外断电时,app数据丢失状况
  6. 网络环境变化时,app的应对状况如何:是否有适当提示?从有网络环境到无网络环境时,app的反馈如何?从无网络环境回到有网络环境时,是否能自动加载数据,多久才能开始加载数据
  7. 多点触摸的状况
  8. 跟其余app之间互相切换时的响应
  9. 进程关闭再从新打开的反馈
  10. IOS系统语言环境变化时

今天的分享就到这里了,未完待续

小编这呢,给你们推荐一个优秀的iOS交流平台,平台里的伙伴们都是很是优秀的iOS开发人员,咱们专一于技术的分享与技巧的交流,你们能够在平台上讨论技术,交流学习。欢迎你们的加入(想要加入的可加小编微信15673450590)。

相关文章
相关标签/搜索