2021年底面试大杂烩
面试公司
一、网易
1、timer
- runloopModel有几种类型:
- 在表中滑动timer切换model,将timer绑定到NSRunLoopCommonModes
runloopmodel平时的状态为DefaultRunLoopMode,在滑动的时候切换成UITrackingRunloopModel,我们使用NSRunloopCommonModes。
runloopModel几种模型:
1、NSDefaultRunLoopMode :默认运行模式
2、NSConnectionReplyMode:Cocoa将此模式与NSConnection对象结合使用来监视回复
3、NSModalPanelRunLoopMode :Cocoa使用此模式来识别用于模式面板的事件。
4、UITrackingRunLoopMode :拖动事件
5、NSRunLoopCommonModes :这是一组可配置的常用模式,占位model
二、花椒直播
1、数组和链表的区别
2、HTTPS、charles操作
Https?
3、数组、字典方法交换具体的方法
数组:交换各个涉及到索引的方法,然后进行判断是否大于当前的count。
字典:后台返回的数据字典的value为nil的时候,取数据的时候会造成崩溃,而在创建的字典赋值nil的时候并不会崩溃,
4、git命令
git log,git commit、git add . git commit. git pull .git push . git status. Git checkout . Git merge . Git branch -a
5、weak原理
runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
Weak表,哈希表、 key:所指对象的地址 value:weak指针的地址数组。
6、Objective-C的动态特性
动态类型:运行时再决定对象的类型。
动态绑定:基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。
动态加载:根据需求加载所需要的资源,这点很容易理解。
7、手机crash日志和解析,除了使用bugly还有什么?
1、通过手机自带的功能,收集crash report。
设置-隐私-分析- 打开 共享iPhone 分析
2、通过DYSM分析。
1、将.ipa文件更名为.crash文件
2、获取闪退的包的dsym,打开xcode, 点击 window - Organizer ,选择你当时打的包的archive - show in Finnder -显示包内容 -dSYMs 文件夹里找到 当时打包的 .dSYM 文件
3、 找到当时打包用的xcode(必须是打包的dev用的那个打包的xcode,(因为一个人可能装了多个版本的xcode)), 前往到 /应用程序,找到symbolicatecrash
https://www.jianshu.com/p/d4946b467cc7
4、把这三个文件复制到同一个文件中,在终端输入命令 ./symbolicatecrash app.crash app.dSYM > crash.log 命令 ,回车键,然后生成crash.log文件,是解析过后的文件。
5、如果有当时打包的源码,将crash.log更名为crash.crash右键打开,选择源码的Xcode,可以直接定位到闪退的地方。
如果没有的话,就直接分析那个方法闪退就行。
8、@interface与** @property**的区别
1)@interface大括号中声明的是“成员变量”;
2)@property声明的是“属性”,
@synthesize与@property配对,意义是“合成”。
成员变量与属性的区别主要分为以下两点:
1、在@interface中定义变量的话,为当前类的私有(private),顾名思义,这些变量只能在当前类中被访问;而用@property声明的变量为公有(public),可以在当前类或者其他类中被访问。
2、使用@interface声明的变量,使用变量名进行访问;@property声明的变量用“
_变量名”(不用@synthesize的方式,后面会提及),或者“self.变量名”的形式进行访问。
9、安装包瘦身
编译器优化:去除异常支持,Enable C++ Exections,Other C flags 添加 -fno-execptions
未使用的代码:利用APPCode检测未使用的代码
LSUnuserdResource、压缩图片、图片转URL
LInkMap:生成LinkMap文件,查看可执行文件大小。针对某个文件和类进行优化。
Mach-O是编译完成的二进制文件,LinkMap是中间产生的如符号表类的文件,这个LinkMap里展示了整个可执行文件的全貌,列出了编译后的每一个 .o 目标文件的信息(包括静态链接库 .a 里的),以及每一个目标文件的代码段、数据段存储详情。
把Write Link Map File 选项设为 yes,并在 Path to Link Map File 中指定好linkMap的存储位置。编译完成之后,即可在存储位置获得 linkMap 文件。
三、白龙云马
1、@synthesize和@dynamic
@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
@dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。
1.@synthesize 的作用:是为属性添加一个实例变量名,或者说别名。同时会为该属性生成 setter/getter 方法。
2.禁止@synthesize:如果某属性已经在某处实现了自己的 setter/getter ,可以使用 @dynamic 来阻止 @synthesize 自动生成新的 setter/getter 覆盖。
3.内存管理:@synthesize 和 ARC 无关。
4.使用:一般情况下无需对属性添加 @synthesize ,但一些特殊情形仍然需要,例如protocol中声明的属性
2、引申出来的问题: 协议中能不能添加属性
OC语言的协议里面是支持声明属性的,而在协议中声明属性其实和在其中定义方法一样只是声明了getter和setter方法,并没有具体实现,所以当这个协议属性修饰符为@ required时,如果不实现编译器就会报出警告,最简单的方式就是加上属性同步语句@synthesize propertyName;
那么在哪里使用嫩????
一般用的场合是,有两个类A和B,如果A和B不是继承关系,想给A和B增加几个相同的属性,可以实现一个协议C,加个属性,然后让A和B都遵循C协议就可以了。当然协议中只是声明了属性,在A和B里还要手动实现以下setter和getter方法才行。
链接:https://www.jianshu.com/p/26735972cfcc
3、实例变量、成员变量和属性变量的区别。
属性变量: 属性是与其他对象交互的变量,会生成默认的setter和getter方法.分类中添加的属性是不会自动生成setter和getter方法的,必须要手动添加
实例变量: class类进行实例化出来的对象为实例对象
成员变量: 在{ }中所声明的变量都是成员变量(实例变量是一种特殊的成员变量)。其中的hell、btn也是实例对象,id是一种特殊的class,是OC特有的对象。成员变量是私有变量,外部不会获取到。
四、MeatAPP
1、你的项目使用的技术栈。
语言
UI
网络
存储
线程、
内寸:
架构:设计模式MVC、MVVM、路由、混合开发
系统:runloop、runtime
安全:应用安全防护、网络安全
代码管理:git
证书发布和管理:上架流程、证书签发流程、审核问题处理。
2、KVC原理
setkey,_key,_isKey、key、isKey的顺序来查找key。
3、UIView和layer的区别
- 从框架上说:
CALayer基于QuartzCore.framework框架
UIView基于UIKit框架
- 从父类上说:
CALayer继承自NSObject
UIView继承自UIResponder
所以,UIView可以处理事件,而CALayer不能处理事件,UIView侧重于对显示内容的管理,CALayer侧重于对内容的绘制。。由于CALayer不需要处理交互事件、所以是轻量级的、性能要比UIView高。
UIView本身,更像是一个CALayer的管理器,访问它的和绘图、坐标相关的属性,如frame,bounds等,实际上内部都是访问它所在CALayer的相关属性
三、搜狐
1、怎么实现两个线程交替打印
使用信号量来控制两个线程的打印顺序。
当信号量大于0时,线程执行。当信号量为0,那么这个函数就阻塞当前线程等待timeout,然后我们又设置信号量为1,那么另一个线程又继续执行。
2、怎么查找崩溃点
1、Xcode的window-organizer,找到Crasher,有崩溃信息。
2、bugly
3、symbolicatecrash crash app dSYM 考到了同一个文件夹下
四、欧科云联
1、property默认的属性
automatic、readwrite、assign
2、sizeToFit、
sizeToFit默认展示原始值
imageView设置sizeToFit就是展示图片的大小。
3、copy和retain的区别
retain :使当前对象的引用计数+1,在oc对象中使用
copy :创建一个对象副本,和调用copy方法的对象不是同一个,常常在NSString中使用
浅复制:浅拷贝也为指针拷贝,拷贝后原来的对象计数器会+1;
深复制(mutablecopy):深拷贝为对象拷贝,原来的对象计数器不变。
4、对称加密、非对称加密
对称加密:是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。
非对称加密:使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。
5、runloop的 source0和source1的区别?
runloop对应不同的model,(五种)
- Source0 是直接添加给 RunLoop 处理的事件,Source0:触摸事件、porformselect ,断点之后,输入bt即可查看打印。
- Source1 是基于port端口的,进程或线程之间的通信。
- Timers:定时器NSTimer
- Observers:监听器,用于监听runloop的状态
6、runloop与线程
- RunLoop对象和线程是一一对应关系;
- RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value;
- 如果没有RunLoop,线程执行完任务就会退出;如果没有RunLoop,主线程执行完main()函数就会退出,程序就不能处于运行状态;
- RunLoop创建时机:线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建;
- RunLoop销毁时机:RunLoop会在线程结束时销毁;
- 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop;
- 主线程的RunLoop对象是在UIApplicationMain中通过[NSRunLoop currentRunLoop]获取,一旦发现它不存在,就会创建RunLoop对象。
原文链接:https://blog.csdn.net/weixin_42350379/article/details/104543751
runloop只能从当前的mode退出切换到另一个mode
7、runloop运行逻辑
- 通知observe:进入runloop
- 通知observe: 即将处理timers
- 通知observe:即将处理sources
- 处理blocks
- 处理source0(可能会再次处理blocks)
- 如果存在source1就处理第八步
- 第七步:通知Observe开始休眠(等待被唤醒)
- 第八步:通知Observe结束休眠(被某个消息唤醒)1、处理timers 2、处理GCD (主线程runloop)3、处理source1
- 处理blocks
- 根据前面的结果决定操作,两种结果 1、返回第二步 2、退出runloop
- 通知observer退出runloop
8、class_ro_t和class_rw_t的区别
class_ro_t存储了当前类在编译期就已经确定的属性、方法以及遵循的协议,里面是没有分类的方法的。
那些运行时添加的方法将会存储在运行时生成的class_rw_t中。
五、南瓜视频
1、方法缓存crash是通过散列表的形式存储使用过的方法
Podspeace:name/version/依赖
六、百姓车联
1、自旋锁、互斥锁
互斥锁:当一个线程获得此锁之后,其他线程再获取将会被阻塞,直到该锁被释放。不会占用资源。
自旋锁:当一个线程获得此锁之后,其他线程将会一直循环查看该锁是否被释放。锁比较适用于锁的持有者保存时间较短的情况下。
优先级反转问题:
如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。导致陷入死锁。
2、在子线程里面使用GCD定时器会导致定时器停止吗?为什么?
NO,NSTimer 的定时器是在 RunLoop 中实现的,由于RunLoop在处理各种任务,所以会造成计时器不够准确。
GCD是基于C语言的,并不在 RunLoop 中实现,所以不受影响。
3、iOS15.0新特性
1、在iOS 15中,UINavigationBar默认为透明。在滑动时会有模糊效果。如果想要一直就是模糊效果,可以通过改变scrollEdgeAppearance属性来实现。
2、iOS 15 UITableView sectionHeader下移22像素
3、URLSession 推出支持 async/await 的 API,包括获取数据、上传与下载
4、UIButton支持更多配置。UIButton.Configuration是一个新的结构体,它指定按钮及其内容的外观和行为。
4、分类、继承、扩展
分类:扩展已有类的功能。但不会对原有类造成影响。
继承:继承的好处:代码重用;继承的缺点:父类的改变影响所有的子类。
扩展: 在.m文件中为类增加私有的成员变量(属性)和方法。
类扩展得到的属性和方法,都是私有的!在外界中无法直接使用,即无法直接get后者set到这些成员。但是可以在.h里提供方法接口来改变这些私有属性的情况。
5、对象的本质
对象的本质是个结构体。TestPerson对象在底层被编译成结构体,其中包含了isa和name两个属性,且isa储存在内存中的第一位。
block的本质是对象
没有访问auto变量的block是__NSGlobalBlock __ ,放在数据段
访问了auto变量的block是__NSStackBlock __
[__NSStackBlock __ copy]操作就变成了__NSMallocBlock __
值捕获、指针捕获(static)、直接访问(区局变量)
6、当block内部访问了对象类型的auto变量时,是否会强引用?
- 如果block在栈空间,不管外部变量是强引用还是弱引用,block都会弱引用访问对象。(栈上的block随时会被销毁,也没必要去强引用其他对象)
- 如果block在堆空间,如果外部强引用,block内部也是强引用;如果外部弱引用,block内部也是弱引用
七、美图
1、
- 首先UIView的setNeedsDisplay和setNeedsLayout方法都是异步执行的。而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以绘制了,而setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据。
- 综上所诉,setNeedsDisplay方便绘图,而layoutSubViews方便出来数据。
-setNeedsLayout方法: 标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用.
-layoutIfNeeded方法:如果有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)
链接:https://www.jianshu.com/p/a84f85729952
-
若使用UIView绘图,只能在drawRect绘图,setNeedsDisplay调用调用drawrect方法进行绘制。
-
setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据。
-
sizeToFit:会计算出最优的 size 而且会改变自己的size
-
sizeThatFits:会计算出最优的 size 但是不会改变 自己的 size
2、显式动画和隐式动画
显式动画是指用户自己通过beginAnimations:context:和commitAnimations创建的动画。
隐式动画是指通过UIView的animateWithDuration:animations:方法创建的动画。
3、UIWebView和WKWebView的区别
UIWebView相比于WKWebView
1.加载速度慢;
2.内存占用多,内存优化困难;
3.如果内存占用过多,还可能因为占用过多被系统kill掉。
4、UIView的方法及执行顺序
-(id)initWithFrame:(CGRect)frame - UIView的指定初始化方法; 总是发送给UIView去初始化, 除非是从一个nib文件中加载的;
-(id)initWithCoder:(NSCoder *)coder - 从nib文件中加载的时候发送此消息给UIView;
-(void)awakeFromNib - 在所有的nib中的对象初始化和连接后将发送此消息; 只适用于从nib加载对象; 如要重写,其中还必须调用父类的awakeFromNib;
-(void)willMoveToSuperview:(UIView *)newSuperview - 在一个子视图将要被添加到另一个视图的时候发送此消息;
-(void)willMoveToWindow:(UIWindow *)newWindow - 在一个视图(或者它的超视图)将要被添加到window的时候发送;
-(void)didMoveToSuperview - 把一个视图插入到视图层级之后发送此消息;
原文链接:https://blog.csdn.net/u012938194/article/details/53391497
八、每日优鲜
UIViewController
九、知乎面试
1、SDWebImage是如何区分不同格式的图片的
根据图像数据第一个字节来判断的!
case 0xFF:
return SDImageFormatJPEG;
2、SDWebImage 缓存图片的名称是怎么确定的!
使用MD5:
- 如果单纯使用 文件名保存,重名的几率很高!
- 使用 MD5 的散列函数!对完整的 URL 进行 md5,结果是一个 32 个字符长度的字符串!
3、SDWebImage 的内存警告是如何处理的!
使用通知中心观察
a. UIApplicationDidReceiveMemoryWarningNotification 调用clearMemory清理缓存
B.UIApplicationWillTerminateNotification 接收到应用程序将要终止通知,执行 cleanDisk 方法,清理磁盘缓存!
C. UIApplicationDidEnterBackgroundNotification 接收到应用程序进入后台通知,backgroundCleanDisk 方法,后台清理磁盘!
4、SDWebImage图片url不变,图片内容改变怎么处理,比如头像。
在调用方法中的options中填写枚举SDWebImageRefreshCached。
6、SDWebImage下载失败怎么处理:
options 传SDWebImageRetryFailed
7、runloop和autorelease
iOS 在主线程的runloop中注册了两个Observe
第一个Observer监听了KCFRunloopEntry事件,会调用objc_autoreleasepoolpush()。
第二个Observe监听了KCFRunloopBeforeWaiting事件,会调用objc_autoreleasepoolpop(),objc_autoreleasepoolpush(),
还监听了KCFRunloopBeforeExting事件,会调用objc_autoreleasepoolpop();
十:顺丰同城
1、响应者链
如果有父视图,nextResponder指向父视图,UIWindow的跟视图,UIwindow、UIApplication。
通过在显示视图层级中依次对视图调用这个 2 个方法来确认该视图是不是能响应这个点击的点,首先会调用 hitTest,然后在 hitTest 中调用 pointInside,最终 hitTest 返回的那个 view 就是最终的响应者Responder。
在显示图层中,依次调用两个方法来确定是不是能响应这个点击的点,先调用hittest然后在hitTest中调用pointInside,最终hitTest返回的的那个View就是最终的响应者Responder.。
// 返回此次触摸事件初始点所在的视图
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
// 返回视图是否包含指定的某个点
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
链接:https://www.jianshu.com/p/1ad168f85bd7
- 寻找事件的响应视图是通过调用视图的 hitTest 和 pointInside 完成的。
- hitTest 的调用顺序是从 UIWindow 开始,对视图的每个子视图依次调用。
- 遍历直到找到响应视图,然后逐级返回最终到 UIWindow 返回此视图,哪怕还有未遍历到的视图,也不会去遍历了。
卡顿优化:
CPU :
1、能用轻量级的对象用轻量级的,可以用CALayer取代UIView
2、不要频繁调用UIView的相关属性
3、提前计算好布局,不要多次修改属性
4、图片的size最好和UIImageView的size保持一致
5、控制最大并发量
6、耗时操作放到子线程:图片处理(解码绘制)、文本处理(尺寸计算)
GPU :
1、减少视图的数量和层次
2、图片纹理尺寸不要太大,最大的处理是4096*4096,一旦大于会占用CPU的资源。
3、减少透明的视图
4、尽量避免离屏渲染:光栅化、遮罩mask、圆角:同时设置:maskToBounds和cornerRadius
可以用CoreGraphics绘制裁剪圆角或者让美工提供圆角图片。
一个地方不要栽两次跟头。
12.13 知乎面试:15:30
12.14 顺丰同城 11:00
12.15 指掌易 15:00
现场面试
12.20
1、神州付 14:30现场面试
金辉大厦 望京东
2、元趣娱乐 17:00 现场面试
北京 朝阳区安定路39号长新大厦1301室
教育公司:
1、23种设计模式
单例模式:
工厂模式:
观察者模式:一对多的依赖关系,一个对象的状态发生改变,所依赖于他的对象都会得到通知自动更新。
代理模式:
装饰模式:动态的给一个对象增加一些额外的职责,就增加的功能来说比生成的子类更加灵活。
腾讯:
1、Hash算法解决冲突
再哈希法:又叫双哈希法,有多个不同的Hash函数,当发生冲突时,使用第二个,第三个,….,等哈希函数
计算地址,直到无冲突。
建立公共溢出区:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
面试日期:2021/12/24 周五
面试时间:10:30
面试方式:现场面试
面试地点:北京市昌平区北京牛电科技有限责任公司
微吼科技
面试日期:2021/12/24 周五
面试时间:14:30
面试方式:现场面试
面试地点:北京市朝阳区紫檀大厦
响应链拉胯,具体的事例分析。
2021.12.27 10:00
动因体育:中轻大厦 A-19
2021.12.27 16:00
新氧:来广营
六大设计原则:
1、单一职责原则
Github token: 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
半年前点点互动面试题:
1、内购流程以及掉单怎么处理?
1、向服务器发送请求,获取产品列表。
2、用户选择产品,向APPStore发送支付请求。
3、APP Store处理支付,并返回支付信息。
4、程序从支付信息获取信息并发送给服务器。
5、服务器进行审查,将数据发给App Store来验证该交易的有效性。
6、服务器返回验证结果,确定用户购买内容。
7、客户端将购买内容传递给程序。购买结束。
丢单处理:
1、在applicationDidFinishLaunch中监听paymentQueue
添加监听
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
监听结果回调
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
[[MLIAPManager sharedManager] paymentQueue:queue updatedTransactions:transactions andFrom:YES];
}
2、客户端在拿到苹果支付票据后,一定要先将支付票据和用户账号做映射,标记为未验证,保存到本地数据库中,然后把票据提交到游戏服务器,在确保得到游戏服务器的反馈,在将本地数据库中该条记录删除,确保游戏服务器收到该票据。
update、订单ID和账号做个映射存储到keychain中,然后在后端请求,成功后删除所有的内容。
2、APP怎么共享数据?
APP共享数据的方式:keychain、剪切板、url scheme、
|
keychain
|
在同一个开发者账号下可以分享数据。
|
|
url scheme
|
1、添加URL Types 2、添加白名单 3、传递的url中拼接的数据可以传递数据
|
|
剪切板
|
app间共享资源的最主流方式
|
|
UIDocumentInteractionController
|
文件的预览分享。不是一个controller,而是继承自NSObject
|
| | |
3、keychain的原理是什么?
字典
- 数据并不存放在App的Sanbox中,即使删除了App,资料依然保存在keychain中。如果重新安装了app,还可以从keychain获取数据。
- keychain的数据可以通过group方式,让程序可以在App间共享。不过得要相同TeamID
- keychain的数据是经过加密的
SecItem有五类:通用密码、互联网密码、证书、密钥和身份。在大多数情况下,我们用到的都是通用密码
3、数据存储的几种方式?
数据存储的方式:keychain、nsuserdefault、sql数据库、归档、coreData、plist存储
4、APP崩溃了怎么保证数据不丢失?
添加监听异常的代码NSUncaughtExceptionHandler,在异常的时候会走这个处理,可在此处进行数据保存。
5、SDK中存储在NSUSerDefault中的数据,有没有可能被其他SDK或者APP清掉?
本APP嵌入的SDK理论上是可能被其他SDK清除掉的。一般SDK存储的时候会对key打上特定的标识。APP存储的时候也要打上特定的标识。
但是绝对不会被其他的APP清除掉,因为每个APP都是一个沙盒Sanbox,他们之间相互独立的。
4、线程的具体应用?
1、串行、并发、依赖、栅栏
2、线程保活
5、怎么防止SDK的崩溃?
1、写个种类别NSArray, NSString来判定边界崩溃问题。
2、使用try catch防止崩溃
6、runtime的应用。
方法交换、添加属性、自动解归档、字典转模型、获取类的所有属性和方法、动态添加方法resolveInstanceMethod
7、SDK 瘦身
1、资源文件可以进一步压缩,压缩图片tynepng
2、Generate Debug Symbols 设置为NO
3、Dead Code Stripping yes
4、尽量自己封装,不要用第三方不过可以设置依赖。