这里包含了去哪儿,滴滴,蚂蚁金服,美团,今日头条,快手以及其它公司的一些面试题,大部分面试官问的重复的问题很多,总体来说就是以下的面试题。
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130595548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
- 简述iOS中的内存管理方式
iOS的内存管理用的是引用计数的方法,分为MRC(手动引用计数)和ARC(自动引用计数)。
MRC:开发者手动地进行retain和release操作,对每个对象的retainCount进行+1,-1操作,当retainCount为0时,系统会自动释放对象内存。
ARC:开发者通过声明对象的属性为strong,weak,retain,assign来管理对象的引用计数,被strong和retain修饰的属性变量系统会自动对所修饰变量的引用计数进行自增自减操作,同样地,retainCount为0时,系统会释放对象内存。
- block的分类,__block的作用,block循环引用产生的原因及解决办法
3.深拷贝与浅拷贝
深拷贝就是开辟一块新的内存空间来存储原来内存空间的内容,对象指针指向新的内存空间。浅拷贝只是重新生成一个指针,指向的还是原来的内存空间。
copy方法:如果是非可扩展类对象,则是浅拷贝。如果是可扩展类对象,则是深拷贝。
mutableCopy方法:无论是可扩展类对象还是不可扩展类对象,都是深拷贝。
注意:深拷贝和深复制不同,深拷贝的内存空间的元素还是指向原地址,但是深复制会开辟新的内存空间重新复制子元素。
4.iOS中常见的属性和默认的对象属性
常见属性: atomic, nonatomic, assign, retain, strong, weak, copy, readonly, readwrite, unsafe_unretained, getter=, setter= 等。
默认属性: 继承于NSObject类的对象:(atomic, strong), 非继承于NSObject类的对象:(atomic, assign)
属性意义:
5.哪些属性需要声明成copy,为什么?
@interface ViewController ()
@property (nonatomic, copy)NSString *aStr;
@property (nonatomic, strong)NSString *bStr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// [self buildUI];
[self testCode];
}
- (void)testCode{
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"%@", @"abc"];
self.aStr = mutableStr;
self.bStr = mutableStr;
[mutableStr appendString:@"123"];
NSLog(@"copy修饰的字符串:%@", self.aStr);
NSLog(@"strong修饰的字符串:%@", self.bStr);
}
打印结果:
2018-05-22 21:13:58.344883 TTFeedBackDemo[1224:245923] copy修饰的字符串:abc
2018-05-22 21:13:58.345004 TTFeedBackDemo[1224:245923] strong修饰的字符串:abc123
用了copy属性修饰之后,可以防止这些类型的对象被引用并且改变内容。
- 通知,代理,block,KVO的使用场景分别是什么,有什么区别?
通知: 适用于毫无关联的页面之间或者系统消息的传递,属于一对多的信息传递关系。例如系统音量的改变,系统状态的改变,应用模式的设置和改变,都比较适合用通知去传递信息。
代理: 一对一的信息传递方式,适用于相互关联的页面之间的信息传递,例如push和present出来的页面和原页面之间的信息传递。
block: 一对一的信息传递方式,效率会比代理要高(毕竟是直接取IMP指针的操作方式)。适用的场景和代理差不多,都是相互关联页面之间的页面传值。
KVO: 属性监听,监听对象的某一属性值的变化状况,当需要监听对象属性改变的时候使用。例如在UIScrollView中,监听contentOffset,既可以用KVO,也可以用代理。但是其他一些情况,比如说UIWebView的加载进度,AVPlayer的播放进度,就只能用KVO来监听了,否则获取不到对应的属性值。
- 简述对OC中的isa指针的认识
Ojective-C语言是基于C语言的封装,它实现了将面向过程的语言向面向对象的语言的转变。而OC中绝大部分类又是继承于NSObject类的,所以研究清楚NSObject类的构成,对于理解OC语言很有帮助。 ##### NSObject类引入了两个头文件:#include
、#include
,第一个头文件引入的是objc结构体的构成方式即isa指针,第二个头文件引入的是Runtime消息查找机制。 ##### 接下来又引入了三个类的声明:@class NSString, NSMethodSignature, NSInvocation;
##### NSMethodSignature和NSInvacation和OC的方法转发机制有关,而NSString是与NSObject的+ (NSString *)description
方法有关。
isa指针: 代码如下
@interface NSObject {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
NSObject对象其实包含了一个Class类型的isa指针。
这个和id类型是一样的,代码如下:
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
即id类型其实是objc_object指针类型的别称。objc_object结构体同样也是包含了一个指向Class类型的指针。
继续看一下,Class isa指针的内部结构,如下
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;//指向元类的Class指针
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;//指向父类的Class指针
const char * _Nonnull name OBJC2_UNAVAILABLE;//类名
long version OBJC2_UNAVAILABLE;//类的版本信息,默认为0
long info OBJC2_UNAVAILABLE;//运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE;//该类的实例变量大小
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;//属性列表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;//方法列表
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;//缓存方法列表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;//协议列表
#endif
} OBJC2_UNAVAILABLE;
typedef struct objc_class *Class;
Class其实就是一个objc_class类型的结构体指针。objc_class的结构体变量构成见上图,下面是objc_class类的super_class指针和isa元类指针的具体指向关系,请大家分清对象,对象的类,元类,根元类这些概念。
- 简述OC中的消息转发机制
当objc_msgSend方法调用找不到响应的函数名称时就会进行消息转发,主要分为3步:
调用方法+(BOOL)resolveInstanceMethod:(SEL)sel
(实例方法动态解析)和+ (BOOL)resolveClassMethod:(SEL)sel
(类方法动态解析)。
调用方法 - (id)forwardingTargetForSelector:(SEL)aSelector
调用方法- (void)forwardInvocation:(NSInvocation *)anInvocation
和- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
具体的转发流程见下图:
- 响应链原理
//判断当前点击事件是否存在最优响应者(First Responder)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
//判断当前点击是否在控件的Bounds之内
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
第一个方法返回一个可以响应event触摸事件的UIView,第二个方法判断触摸点位在不在可相应范围之内的BOOL值。所以会衍生出一些问题,比如说“如何让一个父视图以外的子视图响应点击事件”,“如何只让一个UIView的圆形区域响应触摸事件”等等,在此由于篇幅限制,不再一一展开详述。下面这幅图简述了系统查找响应事件控件的流程。
- 手写一个block结构体声明
typedef void(^RBBlogDemoHandler)(void);
- RunLoop原理,RunLoop与线程的关系
- GCD与NSOperation两种管理多线程方式的异同点
- GCD的常用api
- GCD中的同步异步,串行并发的概念,GCD常见的线程死锁问题
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@", @"123");
});
这样的函数,就是典型的GCD死锁函数。 因为dispatch_sync阻塞的当前的线程,而当前线程是main_queue,也就是说是一个串行线程,当前线程只有先执行NSLog(@"%@", @"123")
才能继续运行下去,但是当前线程又被阻塞掉了,无法向下继续执行,所以这就是一个死锁的GCD执行函数了。
- iOS中常用的线程锁有哪些,分别具有哪些特点?
dispatch_barrier_async
/dispatch_barrier_sync
,dispatch_barrier_async
/dispatch_barrier_sync
在一定的基础上也可以做线程同步,会在线程队列中打断其他线程执行当前任务。两个的区别是dispatch_barrier_async阻塞的是当前队列的线程,而dispatch_barrier_sync阻塞的是任务所插入队列的线程。
- Father的子类Son,分别写出
NSStringFromClass([self class])
,NSStringFromClass([super class])
,NSStringFromClass(self.superClass)
的打印值
- KVO的原理
willChangeValueForKey:
(值改变之前)和didChangevlueForKey:
(值改变之后)。在一个被观察属性发生改变之前,willChangeValueForKey:
一定会被调用,这就会记录旧的值。而当改变发生后,didChangeValueForKey:
会被调用,继而observeValueForKey:ofObject:change:context:
也会被调用。
- runtime的机制和应用
19.MJExtension, MJRefresh, SDWebImage的实现原理
- NSTimer计时器是准确的吗,为什么?
- 类的分类和类的扩展的区别,类的分类的实现原理。
类的分类可以动态添加方法(运行时),类的扩展可以添加更多的属性变量(编译期)。
类的分类的实现原理:在运行时过程中,本类的方法加载完毕之后,会查询是否有类的分类,如果有类的分类,就会再去加载类的分类的方法,把这些方法全部存储到objc_class结构体的methodLists数组中。注意,这里的类的分类的方法是插入到数组的第一个元素位置的,也就是说类的分类的方法会覆盖本类的同名方法。如果有多个类的分类都包含同名函数,那么最后一个被加载进compile sources的类的分类文件中的方法将会覆盖其他的同名方法。
- iOS动态关联属性(
objc_setAssociatedObject
,objc_getAssocicatedObject
)的实现原理
- Masonry的抗压缩属性和抗拉伸属性
[label1 setContentHuggingPriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal];
[label2 setContentHuggingPriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[label1 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[label2 setContentCompressionResistancePriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal];
- 加密的种类,对称加密和非对称加密
- 解释一下七层网络结构,三次握手协议和四次挥手协议
七层网络协议:
三次握手协议:
四次挥手协议:
- http和https的区别
- https双向验证原理
1.浏览器将自己支持的一套加密规则发送给网站。
2.网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
3.浏览器获得网站证书之后浏览器要做以下工作:
4.网站接收浏览器发来的数据之后要做以下的操作:
5.浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
具体的流程见下图:
- HTTP常用的头部字段,常见的返回状态码和意义
常见的头部字段:
返回的状态码:
- @class和import以及include的区别
- weak对象的管理方式
weak是弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil。runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
- iOS的retain和release的操作是在编译期还是运行时进行的
- (void) setUserName:(UITextField *)userName {
[_userName release];
_userName = [userName retain];
}
- +(void)load方法和+(void)initial方法的异同
iOS会在应用程序启动的时候调用load方法,在main函数之前调用 执行子类的load方法前,会先执行所有超类的load方法,顺序为父类->子类->分类 在load方法中使用其他类是不安全的,因为会调用其他类的load方法,而如果关系复杂的话,就无法判断出各个类的载入顺序,类只有初始化完成后,类实例才能进行正常使用 load 方法不遵从继承规则,如果类本身没有实现load方法,那么系统就不会调用,不管父类有没有实现(跟下文的initialize有明显区别) 尽可能的精简load方法,因为整个应用程序在执行load方法时会阻塞,即,程序会阻塞直到所有类的load方法执行完毕,才会继续 load 方法中最常用的就是方法交换method swizzling。
惰性调用,只有当程序使用相关类时,才会调用 运行期系统会确保initialize方法是在线程安全的环境中执行,即,只有执行initialize的那个线程可以操作类或类实例。其他线程都要先阻塞,等待initialize执行完。如果类未实现initialize方法,而其超类实现了,那么会运行超类的实现代码,而且会运行两次。initialize方法是线程安全的,可以用来设置内部数据,比如,某个全局状态,如数组、字典等无法在编译期初始化,可以放在initialize里面。
当一个视图控制器被创建,并在屏幕上现实的时候。代码的执行顺序:
当一个视图被移除屏幕并且销毁的时候执行顺序:
- iOS中各类控件的继承树关系
- 如何化解NSTimer的循环引用关系
首先要理解NSTimer为什么会引起循环引用:NSTimer和使用Timer的ViewController相互持有。
解决办法有两个:
- 怎样管理第三方SDK,CocoaPods和Carthage的异同
iOS中一般使用CocoaPods和Carthage来管理第三方SDK。
两者的比较:
- -(BOOL)isKindOfClass和-(BOOL)isMemberOfClass的区别
-(BOOL) isKindOfClass: classObj 判断是否是这个类或者这个类的子类的实例
-(BOOL) isMemberOfClass: classObj 判断是否是这个类的实例
- 数据持久化的几种方式和对应的应用场景
- 如何实现一个完整的单例
#import "Singleton.h"
@interface Singleton()
@end
@implementation Singleton
static Singleton* _instance = nil;
+(instancetype) shareInstance
{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init] ;
//不是使用alloc方法,而是调用[[super allocWithZone:NULL] init]
//已经重载allocWithZone基本的对象分配方法,所以要借用父类(NSObject)的功能来帮助出处理底层内存分配的杂物
}) ;
return _instance ;
}
+(id) allocWithZone:(struct _NSZone *)zone
{
return [Singleton shareInstance] ;
}
-(id) copyWithZone:(NSZone *)zone
{
return [Singleton shareInstance] ;//return _instance;
}
-(id) mutablecopyWithZone:(NSZone *)zone
{
return [Singleton shareInstance] ;
}
@end
- iOS的系统单例有哪些?
[UIScreen mainScreen] (应用程序窗口)
[UIDevice currentDevice] (当前设备)
[UIApplication sharedApplication] (应用程序实例)
[NSNotificationCenter defaultCenter] (消息中心):
[NSFileManager defaultManager] (文件管理):
[NSUserDefaults standardUserDefaults] (应用程序设置):
[NSURLCache sharedURLCache] (请求缓存):
[NSHTTPCookieStorage sharedHTTPCookieStorage] (应用程序cookies池)
- APP启动主要流程
- iOS的沙盒机制
出于安全考虑,iPhone对于安装在上面的应用程序有所限制,这个限制就是应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本文件等。总体来说沙盒就是一种独立、安全、封闭的空间。沙盒(sandbox)的核心内容是:sandbox对应用程序执行各种操作的权限限制。
沙盒的特点:
应用程序沙盒目录下有三个文件夹Documents、Library(下面有Caches和Preferences目录)、tmp。
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130595548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)