自学内容网 自学内容网

2024最新!!!iOS高级面试题,全!(一)

TCP,HTTP,HTTPS,,WebSokect 区别:
IP协议(网络层协议)
TCP:传输控制协议,主要解决数据如何在网络中传输,面向连接,可靠。(传输层协议)
UDP:用户数据报协议,面向数据报,不可靠。
HTTP:主要解决如何包装数据。(应用层协议)
Socket:是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。(传输层协议)
HTTP连接:超文本传输协议,是短连接,客户端向服务器发送一次请求,服务器端响应连接后会立即断掉。数据明文传输,所以会被抓包导致信息泄露,有安全风险问题!
2.Https 则是具有安全性的SSL加密传输协议,需要证书
Socket连接:长连接,理论上客户端和服务器端一旦建立连接将不会主动端掉。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
Socket是传输控制层协议,WebSocket是应用层协议。
 应用程序的生命周期,主要是什么:
application:willFinishLaunchingWithOptions: 程序启动
application:didFinishLaunchingWithOptions: 入口,只执行一次,启动完成准备开始运行
applicationWillResignActive: 切换到非活动状态,如按下home键、切换程序
applicationDidBecomeActive: 切换到激活状态
applicationDidEnterBackground: 应用程序进入后台
applicationWillEnterForeground: 应用程序将要被激活
applicationWillTerminate: 应用程序将要退出
iOS的核心动画:
动画有两种基本类型:隐式动画(一直存在,需要手动关闭)和显式动画(不存在,需要手动创建)
在核心动画中,动画的实现原理是通过不断地修改CALayer的属性值来实现的。在实际使用中,我们通常使用animateWithDuration:animations:来创建核心动画。这些方法内部会自动创建核心动画,并将其添加到视图的CALayer中。
动画的基本流程如下:
创建动画对象:通过UIView的动画方法创建动画对象。
指定动画属性:设置动画对象所要改变的属性值。
指定动画时长:设置动画对象的持续时间。
指定动画曲线:设置动画对象的动画曲线,用于控制动画的速度。
指定动画完成后的操作:设置动画结束后需要执行的操作。
开始动画:将动画对象添加到视图的CALayer中,开始动画。
CAAnimation动画分类:
1.基础动画(如物品放入购物车进行移动)( CABasicAnimation)
2.关键帧动画,图片帧(如人、动物走动)( CAKeyframAnimation)
3.转场动画(一个到另一个场景,如翻页)( CATransition)
4.组合动画( CAAnimationGroup
可以做动画的值:
1.形状系列:frame bounds
2.位置系列:center
3.色彩系列:alpha color
4.角度系列:transform(旋转的角度)
在一个HTTPS连接的网络中,输入账号和密码并单击登陆按钮后,到服务器返回这个请求前,这期间经历了?
1 客户端打包请求。包括URL、端口、账号和密码等。使用POST加载到body中,发送给服务器
服务器端接受请求,返回数字证书。
3 客户端根据收到的证书,生成加密信息。并发送加密信息。
服务端解锁加密信息,然后返回给客户端。
5 客户端解锁返回信息。将内容显示在浏览器上。
链表和数组有什么区别
数组和链表有以下不同:
(1)存储形式:数组是一块连续的空间,声明时就要确定长度。链表是一块可不连续的动态空间,长度可变,每个节点要保存相邻结点指针;
(2)数据查找:数组的线性查找速度快,查找操作直接使用偏移地址。链表需要按顺序检索结点,效率低;
(3)数据插入或删除:链表可以快速插入和删除结点,而数组则可能需要大量数据移动;
(4)越界问题:链表不存在越界问题,数组有越界问题。
数组便于查询,链表便于插入删除。数组节省空间但是长度固定,链表虽然变长但是占了更多的存储空间。
Load和initialize的不同
调用顺序不同,以main函数为分界,+load方法在main函数之前执行,+initialize在main函数之后执行。
子类中没有实现+load方法的话,子类不会调用父类的+load方法;而子类如果没有实现+initialize方法的话,也会自动调用父类的+initialize方法。
+load方法是在类被装在进来的时候就会调用,+initialize在实例化对象的时候调用,并且只会调用一次,是懒加载模式,如果这个类一直没有使用,就不回调用到+initialize方法。
多线程的实际应用场景,回到主线程的方法
回到主线程的方法是performSelectorOnMainTread
延时执行的代码:performSelector:onThread:withObject:waitUntillDone:
使用GCD回到主线程的方法:dispatch_get_main_queue()
使用GCD开启线程:dispatch_async([əˈsɪŋk] )
二者的区别:**dispatch_async()**不受运行循环模式的影响

GCD的深入解析:
最多支持创建64个线程
GCD中有两个核心概念,队列和任务。队列其实就是线程池,存放着任务,队列分串行队列和并发队列。任务是线程执行的代码,在队列中执行任务有两种方式:同步执行和异步执行。
串行队列:按顺序执行。
并发队列:同一时间间隔执行多个任务
* 并行是真的有多个CPU 同时处理任务(多个线程在不同核上跑)
* 并发是只有一个CPU ,单核高频切换任务,使用户觉得多个任务同时执行
* 并行是同一时间执行多个任务
* 并发是同一一时间间隔,执行多个任务
同步执行:不会开启新的线程,任务按顺序执行。
异步执行:会开启新的线程,任务可以并发执行。
区别:会不会开启新的线程。
组合:
同步串行队列:one by one
异步串行队列:one by one (因为前一个任务不执行完毕,队列不会调度)
同步并行队列:one by one (因为同步执行不会开启新的线程)
异步并发队列:可以实现任务的并发,经常用到
主队列:主队列是串行队列,只有一个主线程,添加到主队列中的任务会在主线程执行。通过dispatch_get_main_queue获取主队列。
全局队列:全局队列是并发队列。可以通过dispatch_get_global_queue获取不同级别的全局队列。
同步主队列:死锁卡住不执行。
主队列异步:one by one (因为没有开启新线程)
barry执行任务函数 它后面的任务等它执行完成之后才会执行
队列组 都执行完毕后,再执行操作
dispatch_barrier_async(栅栏函数)的作用是什么?
作用:1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。2.避免数据竞争
多线程是如何产生死锁和死锁的原因:
所谓死锁: 是指两个或两个以上的进程(线程)在执行过程中,因争夺资源(如数据源,内存等,变量不是资源)而造成的一种互相等待的现象
主线程串行队列同步执行任务,会产生死锁
死锁形成的原因:系统资源不足; 进程(线程)推进的顺序不恰当; 资源分配不当
死锁形成的条件:
互斥: 一个资源每次都只能被一个进程占用。
占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
不可抢占:别人已经占有了某项资源,你不能因为自己需要资源而去抢占其他资源。
循环等待: 存在一个进程链,使得每个进程都占有下一个进程所需要的至少一种资源。
多线程的区别和联系
iOS多线程技术有哪几种方式?
答:pthread、NSThread、GCD、NSOperation
NsTread,属于轻量级的,需要手动管理线程周期。GCD是基于c语言的线程,自动管理线程周期。NSOpreation是基于GCD封装的,具有更多的功能。
消息发送机制流程:
消息机制-objc_msgSend的执行流程,分为消息发送、动态方法解析、消息转发三个阶段
消息发送:当调用某个对象的方法的时候,会通过isa指针找到该类的cache缓存列表中查找,如果没有找到就去方法列表中查找,如果还没有找到就去他的父类中查找,直到最后查找到后为nil。
然后就调用动态解析方法。(是指在运行时通过类的resolvemethd方法动态为这个这个方法创建实现,如果还是没有找到,)
最后通过消息转发,把这个消息发送给其他对象来找这个方法。最后还没找到,就会抛出异常。
动态库与静态库的区别。
编译方式不同。静态库是在编译时将库的代码打包到可执行程序中,动态库则是在运行时动态加载到程序中的。
iOS中分类(category)和类扩展(Extension)的区别
1、类别原则上只能添加方法而不能添加属性(能添加属性的原因只是通过runtime解决无setter/getter方法的问题
2、类扩展不仅可以增加方法,还可以增加实例变量(或者属性),只是该变量默认是@private类型的。
3、类扩展中声明的方法没被实现,编译器会报警,但是类别中的方法没被实现编译器是不会有任何警告的,这是因为类扩展是在编译阶段被添加到类中,而分类是在运行时添加到类中。
4、类扩展不能像类别那样拥有独立的实现部分(@implementation部分),和本类共享一个实现。也就是说,类扩展所声明的方法必须依托对应宿主类的实现部分来实现。
属性关键字 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,效率高。
.怎么用 copy 关键字?
不可变类型,使用copy ,出来的都是浅拷贝。mutablecopy ,出来的都是浅拷贝
2. block 也经常使用 copy 关键字。
block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。
具体步骤:1. 需声明该类遵从 NSCopying 协议2. 实现 NSCopying 协议的方法。
.用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?
答:如果我们使用是 strong ,那么这个属性赋值为可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
.浅拷贝和深拷贝的区别?
浅拷贝:只复制指向对象的指针,而不复制引用对象本身。
深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。
区别是会不会生成一个新的对象
这个写法会出什么问题:
@property (nonatomic, copy) NSMutableArray *arr;
问题:添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃。
原因:是因为 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。
常见的 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 声明的对象有什么特性?IOS开发之__bridge,__bridge_transfer和__bridge_retained
id 声明的对象具有运行时的特性,即可以指向任意类型的Objcetive-C的对象
__bridge 关键字来实现id类型与void*类型的相互转换
__bridge_retained:类型被转换时,其对象的所有权也将被变换后变量所持有
__bridge_transfer:在类型转换后,让其释放原先所有权的时候
Objective-C 如何对内存管理的,说说你的看法和解决方法?
答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响
HTTPS和HTTP的区别
  1) https协议需要到ca申请证书,一般免费证书很少,需要交费。
  2) http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
  3) http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4) http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
为什么我们常见的delegate属性都用是weak而不是retain/strong?
答:是为了防止delegate两端产生不必要的循环引用。@property (nonatomic, weak) id<UITableViewDelegate> delegate;
.delegate Notification KVO 区别
KVO适合多对一的监听。delegate基于协议protocol实现,一对一通信。notification通知中心,多对一通信
开发中常用的锁有如下几种:
@synchronized.  NSLock 对象锁  .NSRecursiveLock 递归锁  .pthread_mutex 互斥锁(C语言) dispatch_semaphore 信号量实现加锁(GCD)
信号量是一个计数器,大于0时继续执行,小于等于0时线程等待,可以通过加减信号量来实现加解锁
KVC的底层实现?
当一个对象调用setValue方法时,方法内部会做以下操作:
1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
KVO内部实现原理
1.KVO是基于runtime机制实现的
2.当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
3.如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
5.键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevalueForKey
你是否接触过OC中的反射机制?简单聊一下概念和使用
1). class反射
    通过类名的字符串形式实例化对象,将类名变为字符串。。 NSClassFromString。NSClassFromString
2). SEL的反射 NSSelectorFromString NSStringFromSelector
const、static、extern  inline简介
const:常
static作静态变量
static与const联合使用:声明一个只读的静态变量
extern作用": 只是用来获取全局变量(包括全局静态变量)的值,不能用于定义变量
extern与const联合使用:在"多个文件中"经常使用的同一个字符串常量,可以使用extern与const组合。
inline.内联函数.作用:替代宏.
inline内联函数的说明
1.内联函数只是我们向编译器提供的申请,编译器不一定采取inline形式调用函数.
2.内联函数不能承载大量的代码.如果内联函数的函数体过大,编译器会自动放弃内联.
3.内联函数内不允许使用循环语句或开关语句.
4.内联函数的定义须在调用之前.
iOS开发中nil、Nil、NULL和[NSNull null]的区别
nil:(定义空实例的id),当一个对象置为nil时,这个对象的内存地址就会被系统收回
Nil:(定义空类的id),nil完全等同于Nil
NULL:返回NSNull的单例实例),是一个简单的空指针
NSNull null:(他是一个oc类,用于表示集合中的空值的对象,比如array)
UIView 和 CALayer 的关系
UIView 负责响应事件,CALayer 负责绘制 UI
UIView 中持有一个 layer 属性
属性引用self.xx与_xx的区别
其中self.xx是调用的xx属性的get/set方法,而_xx则只是使用成员变量_xx,并不会调用get/set方法
属性有get set方法,成员变量无
.iOS开发中id,NSObject *,id,instancetype四者有什么区别
instancetype 和 id 都是万能指针,指向对象。
不同点:1.id在编译的时候不能判断对象的真实类型,instancetype在编译的时候可以判断对象的真实类型
2.id可以用来定义变量,可以作为返回值类型,可以作为形参类型;instancetype只能作为返回值类型
什么是谓词?NSPredicate 相当于过滤器
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF > 2 && SELF < 5"];
    NSArray *filterArray = [testArray filteredArrayUsingPredicate:predicate];
如何访问并修改一个类的私有属性?
1.KVC。我们可以用setValue:的方法设置私有属性,并利用valueForKey:的方法访问私有属性。
2.runtime。我们可以利用runtime获取某个类的所有属性(私有属性、非私有属性),在获取到某个类的属性后就可以对该属性进行访问以及修改了。
一个objc对象的isa的指针指向什么?有什么作用?
类的isa指向元类(meta class),元类isa指向元类的根类isa:是一个Class 类型的指针. isa帮助一个对象找到它的方法。每个实例对象有个isa的指针
.isKindOfClass、isMemberOfClass、selector作用分别是什么
isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。
isMemberOfClass:某个对象确切属于某个类型。
selector:通过方法名,获取在内存中的函数的入口地址。
delegate 和 notification 的区别
1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。
2). notification通过维护一个array,实现一对多消息的转发。
3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。
Objective-C的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?
:Objective-C的类不可以多重继承;可以实现多个接口(协议);Category是类别;一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
Objective-C 如何对内存管理的,说说你的看法和解决方法?
Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
3). 内存释放池Release Pool
.iOS开发之layoutSubviews的作用和调用机制
1、layoutSubviews作用
layoutSubviews:想更新子视图的位置的时候,可以通过调用layoutSubviews方法,即可以实现对子视图重新布局。 
2、layoutSubviews调用机制
①、直接调用setLayoutSubviews。
②、addSubview的时候触发layoutSubviews。
③、当view的frame发生改变的时候触发layoutSubviews。
④、第一次滑动UIScrollView的时候触发layoutSubviews。
⑤、旋转Screen会触发父UIView上的layoutSubviews事件。
⑥、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
init初始化不会触发layoutSubviews,但是使用initWithFrame进行初始化时,当rect的值不为CGRectZero时,也会触发。
3、其他
①、- (void)layoutSubviews;这个方法,默认没有做任何事情,需要子类进行重写;
②、- (void)setNeedsLayout;标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用;
③、- (void)layoutIfNeeded;如果,有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)。
.BAD_ACCESS在什么情况下出现?这种问题在开发时经常遇到。原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。
iOS的沙盒目录结构是怎样的?
1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过)
3). Library:
        Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
        Preference:设置目录,iCloud会备份设置信息。
4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
四.用dispatch_source实现可取消的定时器
NStimer,CADisplayLink,GCD Timer
CADisplayLink 是一个保持屏幕同频率的计时器类,一般用在动画或者视频的渲染,不是作为定时器事件来用的。
GCD Timer,GCD的定时器不受影响,因为RunLoop也是基于GCD的
在手势对象基础类UIGestureRecognizer的常用子类手势类型中哪两个手势发生后,响应只会执行一次?
答:UITapGestureRecognizer,UISwipeGestureRecognizer是一次性手势,手势发生后,响应只会执行一次。
请简单的介绍下APNS发送系统消息的机制
APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。
APNS的原理:
    1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)
    2). 应用程序接收到设备令牌并发送给自己的后台服务器
    3). 服务器把要推送的内容和设备发送给APNS
    4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示
内存泄漏检查
静态分析方法(Analyze)和动态分析方法(Instrument的leak)。
Analyze 优点:
2、能够在编码阶段,开发自行进行代码检查。早期发现代码隐患。
3、直接分析源代码来发现程序中的错误,而不需要实际运行。
4、自动检测Objective-C程序中的BUG,发现内存泄露和其它问题。
5、内存问题发现越早,解决的代价就越小。
主要分析以下四种问题:
1、逻辑错误:访问空指针或未初始化的变量等;2、内存管理错误:如内存泄漏等;3、声明错误:从未使用过的变量;4、Api调用错误:未包含使用的库和框架。
Instruments里面工具很多,常用:1). Time Profiler: 性能分析2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。3). Allocations:用来检查内存,写算法的那批人也用这个来检查。4). Leaks:检查内存,看是否有内存泄露。
iOS中的事件的产生和传递
1.事件的产生
发生触摸事件后,加入到UIApplication队列中,将事件分发下去,先发送事件给应用程序的主窗口(keyWindow)。
主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。
找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。
2.事件的传递
触摸事件的传递是从父控件传递到子控件
也就是UIApplication->window->寻找处理事件最合适的view
注 意: 如果父控件不能接受触摸事件,那么子控件就不可能接收到触摸事件
应用如何找到最合适的控件来处理事件?
1.首先判断主窗口(keyWindow)自己是否能接受触摸事件
2.判断触摸点是否在自己身上
3.子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素,然后执行1、2步骤)
4.view,比如叫做fitView,那么会把这个事件交给这个fitView,再遍历这个fitView的子控件,直至没有更合适的view为止。
5.如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。
UIView不能接收触摸事件的三种情况:
不允许交互:userInteractionEnabled = NO
隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。
事件传递后触发响应者链条
响应者链条是由很多UIResponder的对象组合起来的链条。
一般是沿着响应者链条向上传递,
传递的过程为:
1.判断当前是否为控制器的view,是,事件就传递给控制器,不是,事件就传递给父控件。
2.在视图层次结构的最顶层,如果也不能处理收到的事件,则将事件传递给window对象处理。
3.如果window对象也不处理,则将事件传递给UIApplication对象。
4.如果UIApplication对象也不处理,则将事件丢弃。
hitTest:withEvent:
这是iOS事件的传递和响应中最重要的方法之一,在前边也有提到,现在来具体的介绍一下这个方法。
只要事件一传递给一个控件,这个控件就会调用自己的hitTest:withEvent:方法。
他的作用就是寻找并返回最适合的view,无论这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传递给这个控件,随后就调用该方法。
事件传递给窗口或控件的后,就调用hitTest:withEvent:方法寻找更合适的view。所以是,先传递事件,再根据事件在自己身上找更合适的view。
不管子控件是不是最合适的view,系统默认都要先把事件传递给子控件,经过子控件调用子控件自己的hitTest:withEvent:方法验证后才知道有没有更合适的view。即便父控件是最合适的view了,子控件的hitTest:withEvent:方法还是会调用,不然怎么知道有没有更合适的!即,如果确定最终父控件是最合适的view,那么该父控件的子控件的hitTest:withEvent:方法也是会被调用的。
如果hitTest:withEvent:方法中返回nil,那么调用该方法的控件本身和其子控件都不是最合适的view,也就是在自己身上没有找到更合适的view。那么最合适的view就是该控件的父控件。
SDWebImage内部实现原理
以Key-Value的形式存储图片。以url 作为key在SDWebImageCache中进行查找,找到后拿出来显示,找不到下载
SDWebImage原理:
调用类别的方法:
1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。3. 从网络上获取,使用,缓存到内存,缓存到沙盒。
GCD中的Block是在堆上还是栈上?堆上。
什么是异步渲染?异步渲染就是在子线程进行绘制,然后拿到主线程显示。
.什么是离屏渲染,什么情况会导致离屏渲染?
显示屏外部,有一部分数据缓冲区,如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域,之后再写入frame buffer,那么这个过程被称之为离屏渲染。
比如阴影/圆角/透明度/毛玻璃
swift oc区别
Swift和Objective-C 共用一套运行时环境,两者可以互相引用混合编程。
其次就是,OC 之前积累的很多类库,在 Swift 中大部分依然可以直接使用。Swift大多数概念与OC一样。
swift引入了可选类型,空安全,元组(tuples)把多个值组合成一个复合值。元组内的值可以使任意类型,并不要求是相同类型
细节使用区别
1、swift不分.h和.m文件 ,一个类只有.swift一个文件,所以整体的文件数量比起OC有一定减少。
2、swift句尾不需要分号 ,除非你想在一行中写三行代码就加分号隔开。
3、swift数据类型都会自动判断 , 只区分变量var 和常量let
4、强制类型转换格式不同 OC强转:(int)a Swift强转:Int(a)
5、关于BOOL类型更加严格 ,Swift不再是OC的非0就是真,而是true才是真false才是假
6、swift的 循环语句中必须加{} 就算只有一行代码也必须要加
7、swift的switch语句后面可以跟各种数据类型了 ,如Int、字符串都行,并且里面不用写break(OC好像不能字符串)
8、swift if后的括号可以省略: if a>b {},而OC里 if后面必须写括号。
9、swift打印 用print("") 打印变量时可以 print("(value)"),不用像OC那样记很多%@,d%等。
10、Swift3的【Any】可以代表任何类型的值,无论是类、枚举、结构体还是任何其他Swift类型,这个对应OC中的【id】类型。
Swift 比 Objective-C 有什么优势?
swift支持空安全,是类型安全的编程语言,代码简介,去掉了.h .m,一个类对应只有一个文件,速度更快,学习成本低
缺点:三方库没有oc的全,想用oc的三方库,只能使用桥接文件实现
Swift 相比 Objective-C 独有的语法
范围运算符
a...b 表示 [a,b] 包括a和b 。 (如3...5 就是范围取3,4,5)
a..<b 表示 [a,b) 包括a,不包括b 。 (如3...5 就是范围取3,4)
常见的如for循环:for i in 0...9{}
独有的元组类型
元组(tuples)把多个值组合成一个复合值。元组内的值可以使任意类型,并不要求是相同类型。eg:
var value = (Int,String) = (x:15,y:"abc")
swift中使用let定义常量,var定义变量
使用常量,更加安全,不能够被修改,在需要对对象进行修改的时候 只能用var修饰.
if let 、 guard let 的用法
缩减代码量,安全处理数据逻辑。
Swift 是面向对象还是函数式的编程语言?
Swift 既是面向对象的,又是函数式的编程语言。
说 Swift 是面向对象的语言,是因为 Swift 支持类的封装、继承、和多态
说 Swift 是函数式编程语言,是因为 Swift 支持 map, reduce, filter, flatmap 这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。
请说明并比较以下关键词:Open, Public, Internal, File-private, Private
访问控制权限,从高到底依次为 Open, Public, Internal, File-private, Private。
他们遵循的基本原则是:高级别的变量不允许被定义为低级别变量的成员变量。
Open 具备最高的访问权限。其修饰的类和方法可以在任意 Module 中被访问和重写。
Public 的权限仅次于 Open。与 Open 唯一的区别在于它修饰的对象可以在任意 Module 中被访问,但不能重写。
Internal 是默认的权限。只能在当前定义的 Module 中访问和重写,它可以被一个 Module 中的多个文件访问,但不可以被其他的 Module 中被访问。
File-private 被修饰的对象只能在当前文件中被使用
Private 是最低的访问权限。它的对象只能在定义的作用域内使用。离开了这个作用域,即使是同一个文件中的其他作用域,也无法访问。
在Swift和Objective-C的混编项目中,如何在Swift文件中调用Objective-C文件中已经定义的方法?如何在Objective-C文件中调用Swift文件中定义的方法?
Swift中若要使用Objective-C代码,可以在ProjectName-Bridging-Header.h里添加Objective-C的头文件名称,Swift文件中即可调用相应的Objective-C代码。一般情况Xcode会在Swift项目中第一次创建Objective-C文件时自动创建ProjectName-Bridging-Header.h文件。
Objective-C中若要调用Swift代码,可以导入Swift生成的头函数ProjectName-Swift.h来实现。
Swift文件中若要规定固定的方法或属性暴露给Objective-C使用,可以在方法或属性前加上@objc来声明。如果该类是NSObject子类,那么Swift会在非private的方法或属性前自动加上@objc。
用Swift 将协议(protocol)中的部分方法设计成可选(optional),该怎样实现?
Swift中,默认所有方法在协议中都是必须实现的。
在协议前加上 @objc ,然后再在方法前加上@objc  optional
swift中,如何阻止一个方法属性,属性,下标被子类改写?
在类的定义中使用final关键字声明类、属性、方法和下标。final声明的类不能被继承,final声明的属性、方法和下标不能被重写。
swift中,关键字 guard 和 defer 的用法
guard也是基于一个表达式的布尔值去判断一段代码是否该被执行。与if语句不同的是,guard只有在条件不满足的时候才会执行这段代码。
guard let name = self.text else {  return }
defer的用法是,这条语句并不会马上执行,而是被推入栈中,直到函数结束时才再次被调用。
struct与class 的区别
struct是值类型,class是引用类型。
值类型的变量直接包含它们的数据,对于值类型都有它们自己的数据副本,因此对一个变量操作不可能影响另一个变量。
引用类型的变量存储对他们的数据引用,因此后者称为对象,因此对一个变量操作可能影响另一个变量所引用的对象。
二者的本质区别:struct是深拷贝,拷贝的是内容;class是浅拷贝,拷贝的是指针。
property的初始化不同:class 在初始化时不能直接把 property 放在 默认的constructor 的参数里,而是需要自己创建一个带参数的constructor;而struct可以,把属性放在默认的constructor 的参数里。
变量赋值方式不同:struct是值拷贝;class是引用拷贝。
immutable变量:swift的可变内容和不可变内容用var和let来甄别,如果初始为let的变量再去修改会发生编译错误。struct遵循这一特性;class不存在这样的问题。
mutating function: struct 和 class 的差別是 struct 的 function 要去改变 property 的值的时候要加上 mutating,而 class 不用。
继承: struct不可以继承,class可以继承。
struct比class更轻量:struct分配在栈中,class分配在堆中
swift把struct作为数据模型
优点
安全性: 因为 Struct 是用值类型传递的,它们没有引用计数。
内存: 由于他们没有引用数,他们不会因为循环引用导致内存泄漏。
速度: 值类型通常来说是以栈的形式分配的,而不是用堆。因此他们比 Class 要快很多!
拷贝:Objective-C 里拷贝一个对象,你必须选用正确的拷贝类型(深拷贝、浅拷贝),而值类型的拷贝则非常轻松!
线程安全: 值类型是自动线程安全的。无论你从哪个线程去访问你的 Struct ,都非常简单。
缺点
Objective-C与swift混合开发:
OC调用的swift代码必须继承于NSObject。
继承:struct不能相互继承。
NSUserDefaults:Struct 不能被序列化成 NSData 对象。
如何设置实时渲染?
@IBDesignable让Interface Bulider在特定视图上执行实时渲染
异步同步任务的区别?
`同步`:等待任务完成,一个接一个,顺可预测(Predictable Execution Order),通常情况在Main
`异步`:不分先后执行顺序完成任务,顺序不可预测(Unpredictable Order),通常在Background
什么是NSError对象?NSError有三部分组成,分别为 Domain Code UserInfo
 Domain是一个字符串,标记一个错误域
NSError(domain: <#String#>, code: <#Int#>, userInfo: <#[String : Any]?#>)
什么是Enum?enum 是一种类型,包含了相关的一组数据
为什么使用synchronized?保证在一定时间内,只有一个线程访问它
strong, weak,copy 有什么不同 strong:引用计数会增加 weak:不会增加引用计数 Copy: 意味着我们在创建对象时复制该对象的值
什么是ABI?应用程序二进制接口
Realm数据库的好处 a. 开源的DB framework b. 快 c. ios 安卓都可以使用
Swift 优势是什么?a. 类型安全 b. 闭包 c. 速度快
什么是泛型? 泛型可以让我们定义出灵活,且可重用的函数和类型,避免重复代码
解释 Swift 中的 lazy?lazy是 Swift 中的一个关键字,他可以延迟属性的初始化时间,知道用到这个属性时,才去加载它
KVC 和 KVO 的区别?
KVC: 它是一种用间接方式访问类的属性的机制 KVO: 它是一种观察者模式,被观察的对象如果有改变,观察者就会收到通知
Gurad的好处? 可以使语句变得更简洁,避免嵌套很多层,可以使用break,return提前退.
 


原文地址:https://blog.csdn.net/u010609022/article/details/142353160

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!