由于之前在公司负责技术面试,因此整理了一份面试题。现在自己也要找工作了,正好看看复习一下相关知识。
1.Block循环引用问题,OC怎么解决?Swift怎么解决?UIView animation为什么没有循环引用?
Block有几种类型?(GlobalBlock StackBlock MallocBlock)
__weak和__block区别?(__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型。__block对象可以在block中被重新赋值,__weak不可以。__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。)
为什么用copy修饰block?ARC下strong行不行?非ARC下retain行不行?为什么?(非ARC下block访问外部局部变量,block存放在栈里面,用copy会把它放在堆里面。ARC下block访问外部局部变量,block存放在堆里面。strong也可以,系统自动做了copy动作,咱们拿到的block已经在堆里了)
2.property属性有哪些修饰符?(getter, setter, atomic, nonatomic, readwrite, readonly, assign, retain, copy, string, weak)
assign和weak的区别
1)weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
2)assigin 可以用非OC对象,而weak必须用于OC对象
NSString用copy和strong修饰有什么问题?
深拷贝(有一个是Mutable就是深拷贝,值拷贝)、浅拷贝(引用拷贝,两个指针指向同一内存地址)的问题。
@synthesize和@dynamic分别有什么作用
1)@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
2)@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
3)@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
3.多线程问题:有几种方式?(pThread, NSThread, GCD, NSOperation)
dispatch_group(下载图片然后处理的问题)
NSOperation(添加依赖:确定执行顺序)
加锁的方式有几种?(@synchronized(id anObject),NSLock, NSRecursiveLock递归锁,NSConditionLock条件锁,NSDistributedLock分布锁,互斥锁,自旋锁)
dispatch_barrier_async的作用是什么?
在并行队列中,为了保持某些任务的顺序,需要等待一些任务完成后才能继续进行,使用 barrier 来等待之前任务完成,避免数据竞争等问题。 dispatch_barrier_async 函数会等待追加到Concurrent Dispatch Queue并行队列中的操作全部执行完之后,然后再执行 dispatch_barrier_async 函数追加的处理,等 dispatch_barrier_async 追加的处理执行结束之后,Concurrent Dispatch Queue才恢复之前的动作继续执行。
category中怎么增加属性?
objc_setAssociatedObject
objc_getAssociatedObject
runloop和线程的关系?
1. 主线程的run loop默认是启动的。main()函数中,重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。
2.对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。
3.在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。
runloop有几种mode?
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
- UITrackingRunLoopMode:ScrollView滑动时
- UIInitializationRunLoopMode:启动时
- NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
内存管理问题:
ARC、MRC内存管理机制
ARC通过什么方式帮助开发者管理内存?
编译时根据代码上下文,插入 retain/release
KVC机制通过key找到value的原理
当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过下面几种不同的方式解析这个调用。
首先查找对象是否带有 someKey 这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。
补充:KVC查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。
KVO的实现方式
当你观察一个对象时,一个新的类会被动态创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。重写的 setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象:值的更改。最后通过 isa 混写(isa-swizzling) 把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。
lldb调试常用命令 breakpoint ni si po p
MVC MVVM设计模式
runtime class 相关
class在runtime中是个什么类型?typedef struct objc_class * Class; 是个objc_class的结构体指针。
objc_class结构体的定义:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
对象的isa指针指向谁?类有没有isa指针?(类) 类的isa指针指向谁?元类有没有isa指针?(元类metaClass)元类的isa指针指向谁?(根元类)根元类有没有isa指针?根元类的isa指针指向谁?(他自己)
super_class 指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL
在objc_class中,所有的成员变量、属性的信息是放在链表ivars中的。
Objective-C不支持往已存在的类中添加实例变量,因此不管是系统库提供的提供的类,还是我们自定义的类,都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话,又应该如何给它添加成员变量呢?这时我们就可以使用class_addIvar函数了。不过需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。另外,这个类也不能是元类。
objc_method_list方法链表中存放的是该类的成员方法(-方法),类方法(+方法)存在meta-class的objc_method_list链表中。
isMemberOfClass 和 isKindOfClass 联系与区别
联系:两者都能检测一个对象是否是某个类的成员
区别:isKindOfClass 不仅用来确定一个对象是否是一个类的成员,也可以用来确定一个对象是否派生自该类的类的成员 ,而isMemberOfClass 只能做到第一点。
举例:如 ClassA派 生 自NSObject 类 , ClassA *a = [ClassA alloc] init];,[a isKindOfClass:[NSObject class]] 可以检查出 a 是否是 NSObject派生类 的成员,但 isMemberOfClass 做不到。
iOS 开发中数据持久性有哪几种?
数据存储的核心都是写文件。
属性列表:只有NSString、NSArray、NSDictionary、NSData可writeToFile;存储依旧是plist文件。plist文件可以存储的7中数据类型:array、dictionary、string、bool、data、date、number。
对象序列化(对象归档):对象序列化通过序列化的形式,键值关系存储到本地,转化成二进制流。通过runtime实现自动化归档/解档,请参考这个文章。实现NSCoding协议必须实现的两个方法:
1.编码(对象序列化):把不能直接存储到plist文件中得到数据,转化为二进制数据,NSData,可以存储到本地;
2.解码(对象反序列化):把二进制数据转化为本来的类型。
SQLite 数据库:大量有规律的数据使用数据库。
CoreData :通过管理对象进行增、删、查、改操作的。它不是一个数据库,不仅可以使用SQLite数据库来保持数据,也可以使用其他的方式来存储数据。如:XML。
Realm
对象可以被copy的条件
只有实现了NSCopying和NSMutableCopying协议的类的对象才能被拷贝,分为不可变拷贝和可变拷贝
- (id)copyWithZone:(NSZone *)zone
TCP和UDP的区别于联系
TCP为传输控制层协议,为面向连接、可靠的、点到点的通信;
UDP为用户数据报协议,非连接的不可靠的点到多点的通信;
TCP侧重可靠传输,UDP侧重快速传输。
TCP连接的三次握手
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN+RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次状态。
Scoket连接和HTTP连接的区别
HTTP协议是基于TCP连接的,是应用层协议,主要解决如何包装数据。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务器不能主动给客户端响应(除非采用HTTP长连接技术),iPhone主要使用类NSURLConnection。
Socket连接:长连接,客户端跟服务器端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务器段保持连接通道,双方可以主动发送数据,一般多用于游戏.Socket默认连接超时时间是30秒,默认大小是8K(理解为一个数据包大小)。
HTTP协议的特点,关于HTTP请求GET和POST的区别
GET和POST的区别:
HTTP超文本传输协议,是短连接,是客户端主动发送请求,服务器做出响应,服务器响应之后,链接断开。HTTP是一个属于应用层面向对象的协议,HTTP有两类报文:请求报文和响应报文。
HTTP请求报文:一个HTTP请求报文由请求行、请求头部、空行和请求数据4部分组成。
HTTP响应报文:由三部分组成:状态行、消息报头、响应正文。
GET请求:参数在地址后拼接,没有请求数据,不安全(因为所有参数都拼接在地址后面),不适合传输大量数据(长度有限制,为1024个字节)。
GET提交、请求的数据会附在URL之后,即把数据放置在HTTP协议头中。
以?分割URL和传输数据,多个参数用&连接。如果数据是英文字母或数字,原样发送,
如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
POST请求:参数在请求数据区放着,相对GET请求更安全,并且数据大小没有限制。把提交的数据放置在HTTP包的包体中.
GET提交的数据会在地址栏显示出来,而POST提交,地址栏不会改变。
传输数据的大小:
GET提交时,传输数据就会受到URL长度限制,POST由于不是通过URL传值,理论上书不受限。
安全性:
POST的安全性要比GET的安全性高;
通过GET提交数据,用户名和密码将明文出现在URL上,比如登陆界面有可能被浏览器缓存。
HTTPS:安全超文本传输协议(Secure Hypertext Transfer Protocol),它是一个安全通信通道,基于HTTP开发,用于客户计算机和服务器之间交换信息,使用安全套结字层(SSI)进行信息交换,即HTTP的安全版。
SVN、Git
Jenkins、Fastlane
推送、IM、地图、bug统计、分享
逆向开发,有没有逆向过别人的代码?怎么写Tweak插件?
安全:防注入、防越狱机器、代码混淆、加密、RSA、DES等
CoreGraphics坐标系和UIkit坐标系不一样,需要转换的问题
视频播放、点播、直播,ijkplayer,FFMPEG,rtmp,rtsp,hls
swift单例:static let shared = ABC()
class和struct的区别:class可以继承,类型转换允许在运行时检查和解释一个类实例的类型,析构器允许一个类实例释放任何其所被分配的资源,引用计数允许对一个类的多次引用。
struct是值类型,class是引用类型
swift中的Extension可以干什么?添加计算型属性和计算型类型属性,定义实例方法和类型方法,提供新的构造器,定义下标,定义和使用新的嵌套类型,使一个已有类型符合某个协议
swift 高阶函数:map, flatmap, reduce, filter
map,flatmap区别:flatmap会过滤掉nil,降维
swift访问权限:
private:private访问级别所修饰的属性或者方法只能在当前类里访问
fileprivate:fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问。
internal:默认访问级别。internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。
public:可以被任何人访问。但其他module中不可以被override和继承,而在module内可以被override和继承。
open:可以被任何人使用,包括override和继承。
final是干什么用的?不允许对其修饰的内容继承或重写
mutating是干嘛用的?修饰枚举和结构体,标识允许修改成员变量内容
defer干嘛用的?推迟执行,函数结束时才执行。
defer{1} defer{2} defer{3}执行顺序,3、2、1
inout干吗用的?传递引用类型,而不是值类型
swift 定义类方法?static 和 class区别?static 方法不可被重写,class方法可以被重写。struct enum 用static, class用class。类的成员变量用static声明。protocol中用static定义类方法,实现时struct enum用static,class可以用static,也可以用class
swift 可选值的概念,swift 可选绑定if let, 强制展开感叹号,带默认值取值:??
swift Tuple 元组
String和NSString最大的区别是什么?String是值类型,NSString是引用类型
try?和try!有什么区别?可选和强制
Typealias有什么用?typealias 是用来为已经存在的类型重新定义名字的,比如网络类中的Success闭包
associatedtype干什么用的?关联类型,协议中声明泛型,需要使用这个关键字
字符串截取怎么做?Swift4.0和上版本Swift在这方面有什么变化?
swift Closure闭包 是引用类型 @escaping什么意思?
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的。
将一个闭包标记为 @escaping 意味着你必须在闭包中显式地引用 self。比如说,在下面的代码中,传递到 someFunctionWithEscapingClosure(_:) 中的闭包是一个逃逸闭包,这意味着它需要显式地引用 self。相对的,传递到 someFunctionWithNonescapingClosure(_:) 中的闭包是一个非逃逸闭包,这意味着它可以隐式引用 self。
swift 泛型:干什么用的?怎么使用?
什么是copy on write:copy on write, 写时复制,简称COW,它通过浅拷贝(shallow copy)只复制引用而避免复制值;当的确需要进行写入操作时,首先进行值拷贝,在对拷贝后的值执行写入操作,这样减少了无谓的复制耗时。
怎么在Swift中使用runtime?继承OC的类,dynamic,@objc
Swift中类似runtime的是什么?Mirror
dynamic的作用:
dynamic 可以用来修饰变量或函数,告诉编译器使用动态分发而不是静态分发。
使用动态分发,可以更好的与OC中runtime的一些特性(如CoreData,KVC/KVO)进行交互
标记为dynamic的变量/函数会隐式的加上@objc关键字,它会使用OC的runtime机制
Optional是用什么实现的?Optional 是个枚举。有两个枚举成员,Some(T) 和 None,通过泛型来兼容所有类型
如何定义下标?使用subscript语法
Swift、OC混编如何操作?Swift通过桥接文件调用OC方法。Objective-C中若要调用Swift代码,可以导入Swift生成的头函数ProjectName-Swift.h来实现。
Swift文件中若要规定固定的方法或属性暴露给Objective-C使用,可以在方法或属性前加上@objc来声明。如果该类是NSObject子类,那么Swift会在非private的方法或属性前自动加上@objc。
library和framework的区别?
Library 仅能包含编译后的代码,即 .a 文件。但一般来说,一个完整的模块不仅有代码,还可能包含 .h 头文修的 、 .nib 视图文件 、 图片资源文件 、 说明文档 。
Framework 作为 Cocoa/Cocoa Touch 中使用的一种资源打包方式,可以上述文件等集中打包在一起,方便开发者使用(就像Bundle)
查看library支持的架构?
lipo -info
library库合并怎么做?
lipo -create liba-arm64.a liba-i386.a -output liba.a
library抽取指定架构怎么做?
lipo liba.a -thin arm64 -output liba-arm64.a
framework合并怎么做?需要和并framework包中的可执行文件,并将两个framework中的Modules里的swiftdoc文件合并到一起
static和dynamic Library的区别是什么?
简单的说,静态链接库是指模块被编译合并到应用中,应用程序本身比较大,但不再需要依赖第三方库。运行多个含有该库的应用时,就会有多个该库的Copy在内存中,冗余。
动态库可以分开发布,在运行时查找并载入到内存,如果有通用的库,可以共用,节省空间和内存。同时库也可以直接单独升级,或作为插件发布。
framework SDK 怎么开放接口?open或public权限,拖入build Phase Public Header。
swift framework SDK 中怎么和OC混编,swift使用OC方法?在framework的umbrella header,比如JYiOSDeviceFingerPrintSDK.h中声明OC文件,再拖到Build Phases中Public Header中。
OC使用swift方法:OC中导入framework库的头文件.h
更好的做法:新建module.modulemap,写入如下内容
module OCSource [system] {
//由于module.modulemap和OCSource.h是在同一个文件夹的,如果不是同一个,路径要写全
header "OCSource.h"
export *
}
CocoaPods私有Spec怎么创建?
怎么进行framework的二进制化?
MVVM,RxSwift的使用?
Swift中常用的第三方框架?
Realm使用方式?怎么实现数据绑定?
模块化/组件化方案?
数据结构和算法,数组、链表、哈希、常用算法、堆、栈等等
编译过程,性能优化,启动速度优化