【面试题】iOS知识大全
iOS知识点大全:
一.Objc三大特性1.封装2.继承3.多态
1> 什么是多态
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。
由于每个类都属于该类的名字空间,这使得多态称为可能。类定义中的名字和类定义外的名字并不会冲突。类的实例变量和类方法有如下特点:
- 和C语言中结构体中的数据成员一样,类的实例变量也位于该类独有的名字空间。
- 类方法也同样位于该类独有的名字空间。与C语言中的方法名不同,类的方法名并不是一个全局符号。一个类中的方法名不会和其他类中同样的方法名冲突。两个完全不同的类可以实现同一个方法。
方法名是对象接口的一部分。对象收到的消息的名字就是调用的方法的名字。因为不同的对象可以有同名的方法,所以对象必须能理解消息的含义。同样的消息发给不同的对象,导致的操作并不相同。
多态的主要好处就是简化了编程接口。它容许在类和类之间重用一些习惯性的命名,而不用为每一个新加的函数命名一个新名字。这样,编程接口就是一些抽象的行为的集合,从而和实现接口的类区分开来。
Objective-C支持方法名的多态,但不支持参数和操作符的多态。
2> OC中如何实现多态
在Objective-C中是通过一个叫做selector的选取器实现的。在Objective-C中,selector有两个意思, 当用在给对象的源码消息时,用来指方法的名字。它也指那个在源码编译后代替方法名的唯一的标识符。 编译后的选择器的类型是SEL有同样名字的方法、也有同样的选择器。你可以使用选择器来调用一个对象的方法。
选取器有以下特点:
* 所有同名的方法拥有同样的选取器
* 所有的选取器都是不一样的
(1) SEL和@selector
选择器的类型是 SEL。@selector指示符用来引用选择器,返回类型是SEL。
例如:
SEL responseSEL;
responseSEL = @selector(loadDataForTableView:);
可以通过字符串来得到选取器,例如:
responseSEL = NSSelectorFromString(@"loadDataForTableView:");
也可以通过反向转换,得到方法名,例如:
NSString *methodName = NSStringFromSelector(responseSEL);
(2) 方法和选取器
选取器确定的是方法名,而不是方法实现。这是多态性和动态绑定的基础,它使得向不同类对象发送相同的消息成为现实;否则,发送 消息和标准C中调用方法就没有区别,也就不可能支持多态性和动态绑定。
另外,同一个类的同名类方法和实例方法拥有相同的选取器。
(3) 方法返回值和参数类型
消息机制通过选取器找到方法的返回值类型和参数类型,因此,动态绑定(例:向id定义的对象发送消息)需要同名方法的实现拥有相 同返回值类型和相同的参数类型;否则,运行时可能出现找不到对应方法的错误。
有一个例外,虽然同名类方法和实例方法拥有相同的选取器,但是它们可以有不同的参数类型和返回值类型。
3> 动态绑定
二.类和对象
1.category
1> 分类拓展协议中哪些可以声明属性?
都可以,但分类和协议创建的属性只相当于方法,但是内部没有对成员变量的操作(无法创建成员变量),拓展可以
代理中声明属性,没有实际创建成员变量,相当于声明了属性名对应的访问方法,遵守协议的类需要实现对应的访问器方法,否则运行报错
分类中声明属性,警告提示需要手动实现访问器方法(Swift中叫计算型属性),而分类中不能创建成员变量,可以在手写访问器方法中使用runtime的 objc_setAssociatedObject方法关联对象间接创建属性(静态库添加属性)
拓展里可以声明属性,直接可以使用
2> 继承和类别的区别
1> 使用继承:
1.1> 添加新方法和父类方法一致,但父类方法仍需要使用
1.2> 添加新属性
2> 类别:
2.1> 针对系统提供的一些类,系统本身不提倡继承,因为这些类的内部实现对继承有所限制(NSString initWithFormat继承崩溃)
2.2> 类别可以将自己构建的类中的方法进行分组,对于大型的类,提高可维护性
3> 分类的作用
将类的实现分散到多个不同文件或多个不同框架中。
创建对私有方法的前向引用。
向对象添加非正式协议。
4> 分类的局限性
无法向类中添加新的实例变量,类别没有位置容纳实例变量。
名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。
无法添加实例变量的局限可以使用字典对象解决.
2.extension
3.protocol
三.Foundation
1.字符串
2.NSArray和NSDictionary
1> iOS遍历数组/字典的方法
数组: for循环 for in enumerateObjectsUsingBlock(正序) enumerateObjectsWithOptions:usingBlock:(多一个遍历选项,不保证顺序)
字典:
1. for(NSString *object in [testDic allValues])
2. for(id akey in [testDic allKeys]){
[sum appendString:[testDic objectForKey:akey]]; }
3. [testDic enumerateKeysAndObjectsUsingBlock:^(idkey,idobj,BOOL*stop) {
[sum appendString:obj]; } ];
速度: 对于数组, 增强for最快,普通for和block速度差不多,增强最快是因为增强for语法会对容器里的元素的内存地址建立缓冲,遍历的时候直接从缓冲中取元素地址而不是通过调用方法来获取,所以效率高.这也是使用增强for时不能在循环体中修改容器元素的原因之一(可以在循环体中添加标记,在循环体外修改元素)
对于字典,allValues最快,allKey和block差不多,原因是allKey需要做objcetForKey的方法
3.NSValue NSNumber
1> 归档视图尺寸,坐标
四.关键字
1.@property
1>readwrite,readonly,assign,retain,copy,nonatomic属性的作用
@property是一个属性访问声明,扩号内支持以下几个属性:
1.1> getter setter
getter=getterName,setter=setterName,设置setter与getter的方法名
1.2> weak assign strong copy
assign 用于非指针变量。用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id,其setter方法直接赋值,不进行任何retain操作
weak 用于指针变量,比assign多了一个功能,当对象消失后自动把指针变成nil,由于消息发送给空对象表示无操作,这样有效的避免了崩溃(野指针),为了解决原类型与循环引用问题
strong 用于指针变量,setter方法对参数进行release旧值再retain新值
copy 用于指针变量,setter方法进行copy操作,与retain处理流程一样,先旧值release,再copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。
1.3> readwrite,readonly,设置可供访问级别
1.4> nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。所以约定俗成只在主线程更新UI,防止多线程设置UI属性,出现资源抢夺现象
2> 如何避免循环引用
两个对象相互强引用,都无法release,解决办法为一个使用strong,一个使用assign(weak)
3> delegate的属性为什么使用assign/weak
避免出现循环引用,场景如UITableViewController强引用视图UITableView,而该视图的代理又是控制器,为避免循环引用,让delegate为弱引用
2.copy
1> copy的使用场景
当多个指针指向同一个对象时,为避免一个指针对对象的改动对其他指针的使用产生影响,使用copy来创建对象的副本
如页面间传值使用copy,A向B控制器传属性(属性为自定义对象),为避免因A的属性变化对B的属性产生影响
再如多人开发或封装库,在不明确传入值为可变还是不可变的情况下,使用copy更安全
2> 什么是深拷贝浅拷贝
对于非容器类对象,不可变对象进行copy操作为浅拷贝,引用计数器加1,其他三种为深拷贝
对于容器类对象,基本和非容器类对象一致,但注意其深拷贝是对象本身是对象复制,其中元素仍为指针复制,系统将initWithArray方法归为了元素深拷贝,但其实如果元素为不可变元素,仍为指针复制,使用归解档可以实现真正的深拷贝,元素也是对象拷贝NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: array]];
3> 字符串什么时候使用copy,strong
属性引用的对象由两种情况,可变和不可变字符串
引用对象不可变情况下,copy和strong一样,copy为浅拷贝
引用对象可变情况下,如果希望属性跟随引用对象变化,使用strong,希望不跟随变化使用copy
4> 字符串所在内存区域
@“abc” 常量区 stringwithformat 堆区
5> mutablecopy和copy @property(copy) NSMutableArray *arr;这样写有什么问题
mutablecopy返回可变对象,copy返回不可变对象
6> 如何让自定义类可以使用copy修饰符
实现<NSCopying>协议,重写copyWithZone方法
五.runtime/消息转发机制
1.runtime http://www.cocoachina.com/ios/20150715/12540.html
1> 什么是runtime
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者,objc_msgSend
2> runtime干什么用,使用场景
runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法现实的, 不好实现)
在程序运行过程中, 动态创建一个类(比如KVO的底层实现) objc_allocateClassPair,class_addIvar,objc_registerClassPair
在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法(修改封装的框架) objc_setAssociatedObject object_setIvar
遍历一个类的所有成员变量(属性)\所有方法(字典转模型,归解档) class_copyIvarList class_copyPropertyList class_copyMethodList
2.消息机制
1> 消息转发的原理
当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的类,然后在类的调度表(dispatch table)中查找selector。如果无法找到selector,objc_msgSend通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找selector,以此类推直到NSObject类。一旦查找到selector,objc_msgSend方法根据调度表的内存地址调用该实现。 通过这种方式,message与方法的真正实现在执行阶段才绑定。
为了保证消息发送与执行的效率,系统会将全部selector和使用过的方法的内存地址缓存起来。每个类都有一个独立的缓存,缓存包含有当前类自己的 selector以及继承自父类的selector。查找调度表(dispatch table)前,消息发送系统首先检查receiver对象的缓存。
缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点点点。
2> SEL isa super cmd 是什么
sel: 一种类型,表示方法名称,类似字符串(可互转)
isa:在方法底层对应的objc_msgSend调用时,会根据isa找到对象所在的类对象,类对象中包含了调度表(dispatch table),该表将类的sel和方法的实际内存地址关联起来
super_class:每一个类中还包含了一个super_class指针,用来指向父类对象
_cmd在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对象实例
IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数.说白了IMP就是实现方法
3> 动态绑定
—在运行时确定要调用的方法
动态绑定将调用方法的确定也推迟到运行时。在编译时,方法的 调用并不和代码绑定在一起,只有在消实发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术,您的代码每次执行都可以得到不同的结果。运行时因 子负责确定消息的接收者和被调用的方法。运行时的消息分发机制为动态绑定提供支持。当您向一个动态类型确定了的对象发送消息时,运行环境系统会通过接收者 的isa指针定位对象的类,并以此为起点确定被调用的方法,方法和消息是动态绑定的。而且,您不必在Objective-C 代码中做任何工作,就可以自动获取动态绑定的好处。您在每次发送消息时,特别是当消息的接收者是动态类型已经确定的对象时,动态绑定就会例行而透明地发生。
六.内存管理
1.内存区域
1>堆和栈的区别
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
2.iOS内存管理
1> 字符串的内存管理
创建字符串的内存空间 堆 常量区
2> 循环引用
delegate属性的内存策略
block循环引用 实际场景
3> autorelease的使用 工厂方法为什么不释放对象 ARC下autorelease的使用场景
避免内存峰值
SDWebimage中加载gif图片 大循环
栈结构 栈顶
统一发release消息
4> ARC和MRC的混用
4.1> MRC>ARC
把MRC的代码转换成ARC的代码,删除内存管理操作(手动)
xcode提供了自动将MRC转换成ARC的功能,操作菜单栏edit -> Refacotor(重构) -> Convert to Objective-C ARC
4.2> ARC>MRC
在ARC项目中继续使用MRC编译的类,在编译选项中标识MRC文件即可"-fno-objc-arc"
在MRC项目中继续使用ARC编译的类在编译选项中标识MRC文件即可"-fobjc-arc"
3.跨平台
3> OC和C框架对象引用
oc和c 桥接 三个桥接关键字都是干么的 __bridge 不更改归属权 __bridge_transfer 所有权给OC __bridge_retain 解除OC的所有权
ios5/6/7/8 内存方面的区别?
ios5.自动引用计数 (ARC)
ios6.UICollectionView ( 内存重用机制,图片展示瀑布流实现 ) 在didReceiveMemoryWarning中处理内存(6之前在ViewDidUnload中) http://blog.csdn.net/likendsl/article/details/8199350
ios7.iOS7以后强制使用ARC
ios8
七.数据传递
1.block
1> block属性为什么用copy?
栈->堆
2> block使用注意什么?
循环引用 修改外部变量
3> block的主要使用场景 ?
动画
数组字典排序遍历
回调状态
错误控制
多线程GCD
4>block原理
block属性是指向结构体的指针,
2.Delegate
4> 什么时候用delegate,什么时候用Notification
delegate针对one-to-one关系,并且reciever可以返回值给sender,notification 可以针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到 reciever的某个功能反馈值,notification用于通知多个object某个事件。
5> delegate和block
block使代码更紧凑,便于阅读,delegate可以设置必选和可选的方法实现,相比block
block可以访存局部变量. 不需要像以前的回调一样,把在操作后所有需要用到的数据封装成特定的数据结构, 你完全可以直接访问局部变量.
3.KVC和KVO
1> 如何调用私有变量 如何修改系统的只读属性 KVC的查找顺序
KVC在某种程度上提供了访问器的替代方案。不过访问器方法是一个很好的东西,以至于只要是有可能,KVC也尽量再访问器方法的帮助下工作。为了设置或者返回对象属性,KVC按顺序使用如下技术:
①检查是否存在-<key>、-is<key>(只针对布尔值有效)或者-get<key>的访问器方法,如果有可能,就是用这些方法返回值;
检查是否存在名为-set<key>:的方法,并使用它做设置值。对于 -get<key>和 -set<key>:方法,将大写Key字符串的第一个字母,并与Cocoa的方法命名保持一致;
②如果上述方法不可用,则检查名为-_<key>、-_is<key>(只针对布尔值有效)、-_get<key>和-_set<key>:方法;
③如果没有找到访问器方法,可以尝试直接访问实例变量。实例变量可以是名为:<key>或_<key>;
④如果仍为找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
2> 什么是键-值,键路径是什么
模型的性质是通过一个简单的键(通常是个字符串)来指定的。视图和控制器通过键来查找相应的属性值。在一个给定的实体中,同一个属性的所有值具有相同的数据类型。键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。
键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的性质是由先前的性质决定的,接下来每个键的值也是相对于其前面的性质。键路径使您可以以独立于模型实现的方式指定相关对象的性质。通过键路径,您可以指定对象图中的一
个任意深度的路径,使其指向相关对象的特定属性。
3> 什么是KVC和KVO
KVC(Key-Value-Coding)内部的实现:一个对象在调用setValue的时候,(1)首先根据方法名找到运行方法的时候所需要的环境参数。(2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。(3)再直接查找得来的具体的方法实现。KVO(Key-Value- Observing):当观察者为一个对象的属性进行了注册,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。所以 isa指针其实不需要指向实例对象真实的类。所以我们的程序最好不要依赖于isa指针。在调用类的方法的时候,最好要明确对象实例的类名
4> kvo的实现机制
当某个类的对象第一次被观察时,系统就会在运行时动态地创建该类的一个派生类,在这个派生类中重写原类中被观察属性的setter方法,派生类在被重写的setter方法实现真正的通知机制(Person->NSKVONotifying_Person).
派生类重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的isa指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对setter的调用就会调用重写的setter,从而激活键值通知机制。此外,派生类还重写了dealloc方法来释放资源。
5> kvo使用场景
①实现上下拉刷新控件 contentoffset
②webview混合排版 contentsize
③监听模型属性实时更新UI
UI
一.控件
1.属性
1> frame和bounds的区别
frame:可表示尺寸和位置,与父视图坐标系的关系,位置以自己的左上角为原点,可用于形变和位移
bounds:可表示尺寸和位置,与自身视图坐标系的关系,大多数情况(滚动视图的子视图等除外)以自己的中心点为原点,可用于形变
center:只表示位置,表示自己中心的坐标,可用于位移
2> trasform
修改位移\形变\旋转,transform不同于board\center\frame,前者中记录的是形变的数据,不发生形变其值是空的,所以我们需要新建结构体,用CGAffineTransform(仿射变换)函数给对象结构体属性赋值,而后者是控件的固有属性,内存数据是始终存在的,当我们用他们做移动等操作时,是改变其值,所以是结构体赋值三步曲,不用CG的函数
使用情景区别: transform一般用于有来有回的变化,而frame是有去无回
2.UITableview
1> 自定义高度
1.1>新建一个继承自UITableViewCell的类
1.2>重写initWithStyle:reuseIdentifier:方法
1.3>添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中)
1.4>进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)
1.5>提供2个模型
数据模型: 存放文字数据\图片数据
frame模型: 存放数据模型\所有子控件的frame\cell的高度
1.6>cell拥有一个frame模型(不要直接拥有数据模型)
1.7>重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame
3.UICollectionView
1> 如何实现瀑布流,流水布局
通过实现UICollectionViewDelegateFlowLayout去改变单元格大小
2> 和UITableView的使用区别
1)必须使用下面的方法进行Cell类的注册:
- - (void)registerClass:forCellWithReuseIdentifier:
- - (void)registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
- - (void)registerNib:forCellWithReuseIdentifier:
2)collectionView与tableView最大的不同点,collectionView必须要使用自己的layout(UICollectionViewLayout)
如:
- UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
- flowLayout.itemSize = CGSizeMake(52, 52); // cell大小
- flowLayout.minimumInteritemSpacing = 1; // cell间距
- flowLayout.minimumLineSpacing = 1; // cell行距
- flowLayout.sectionInset = (UIEdgeInsets){81,1,1,1}; // cell边距
创建collectionView需要带Layout的初始化方法:
- - (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
二.生命周期
1> 应用的生命周期
各个程序运行状态时代理的回调:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions 告诉代理进程启动但还没进入状态保存
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 告诉代理启动基本完成程序准备开始运行
- (void)applicationWillResignActive:(UIApplication *)application 当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了
- (void)applicationDidBecomeActive:(UIApplication *)application 当应用程序入活动状态执行,这个刚好跟上面那个方法相反
- (void)applicationDidEnterBackground:(UIApplication *)application 当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可
- (void)applicationWillEnterForeground:(UIApplication *)application 当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。
- (void)applicationWillTerminate:(UIApplication *)application 当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。
2> 视图的生命周期
loadView - 默认调用super方法,根据控制器创建方式加载视图,重写后将根据重写方法创建视图
viewDidLoad-视图加载完成
viewWillAppear-UIViewController对象的视图即将加入窗口时调用;
viewDidApper-UIViewController对象的视图已经加入到窗口时调用;
viewWillDisappear-UIViewController对象的视图即将消失、被覆盖或是隐藏时调用;
viewDidDisappear-UIViewController对象的视图已经消失、被覆盖或是隐藏时调用;
viewVillUnload-当内存过低时,需要释放一些不需要使用的视图时,即将释放时调用;
viewDidUnload-当内存过低,释放一些不需要的视图时调用。
四.核心绘图
6> View和layer的区别
图层不会直接渲染到屏幕上,UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器。一个UIView上可以有n个CALayer,每个layer显示一种东西,增强UIView的展现能力。
6.1>都可以显示屏幕效果
6.2> 如果需要用户交互就要用UIVIew,其可接收触摸事件(继承UIResponder),而CALayer不能接收触摸事件
6.3> 如果没有用户交互可选用CALayer,因为其所在库较小,占用的资源较少
7> new和alloc init的区别
采用new的方式只能采用默认的init方法完成初始化,采用alloc的方式可以用其他定制的初始化方法。
六.事件处理
1> 描述响应者链条
当触摸事件发生时,压力转为电信号,iOS系统将产生UIEvent对象,记录事件产生的时间和类型,然后系统将事件加入到一个由UIApplication管理的事件队列中。
UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件(从父到子,从后到前),这也是整个事件处理过程的第一步
找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理
4.Runloop
1> 每个线程上都有一个runloop,主线程默认开启,辅助线程需要手动开启,主要用于
- 使用端口或自定义输入源来和其他线程通信
- 使用线程的定时器
- Cocoa中使用任何performSelector…的方法
- 使线程周期性工作
七.屏幕适配
多线程
一.资源抢夺
2> 资源抢夺解决方案
@sychronized{ }
dispatch_barrier_async
NSLock NSCondition
dispatch_semaphore_wait
二.iOS多线程技术
3> 对比iOS中的多线程技术
3.1> pthread
pthread跨平台,使用难度大,需要手动管理线程生命周期
pthread_create创建线程,传参线程标记,线程属性,初始函数,函数参数
3.2> NSThread
NSThread需要手动管理线程生命周期和
3.3> GCD
3.4> NSOperation
GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
3.2> GCD仅仅支持FIFO队列,只可以设置队列的优先级,而NSOperationQueue中的每一个任务都可以被重新设置优先级(setQueuePriority:),从而实现不同操作的执行顺序调整
3.3> GCD不支持异步操作之间的依赖关系设置。如果某个操作的依赖另一个操作的数据,使用NSOperationQueue能够设置依赖按照正确的顺序执行操作(addDependency:)。GCD则没有内建的依赖关系支持(只能通过Barrior和同步任务手动实现)。
3.4> NSOperationQueue方便停止队列中的任务(cancelAllOperations, suspended),GCD不方便停止队列中的任务.
3.5> NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
3.6> GCD的执行速度比NSOperationQueue快
3.7> NSOperationQueue可设置最大并发数量(节电),GCD具有dispatch_once(只执行一次,单例)和dispatch_after(延迟执行)功能
3.8> NSObject分类(perform)和NSThread遇到对象分配需要手动内存管理,手动管理线程生命周期
3.9> NSThread查看线程
3.10> NSObject分类线程通信
4> 原子属性
原子属性采用的是"多读单写"机制的多线程策略
"多读单写"缩小了锁范围,比互斥锁的性能好
规定只在主线程更新UI,就是因为如果在多线程中更新,就需要给UI对象加锁,防止资源抢占写入错误,但是这样会降低UI交互的性能,所以ios设计让所有UI对象都是非线程安全的(不加锁),并规定只在主线程中更新UI,规避多线程抢占资源问题
三.其他
5> 多线程优缺点
优点:
使应用程序的响应速度更快,用户界面在进行其他工作的同时仍始终保持活动状态;
优化任务执行,适当提高资源利用率(cpu, 内存);
缺点:
线程占用内存空间,管理线程需要额外的CPU开销,开启大量线程,降低程序性能;
增加程序复杂度,如线程间通信,多线程的资源共享等;
1> 在多线程中使用通知需要注意什么问题?
网络
一.网络基础
1.数据解析
1> XML解析方式
SAX 方式解析
-只读
-速度快
-从上向下
-通过5个代理方法解析,每个代理方中都需要写一些代码!
-如果要实现SAX解析,思路最重要!
-适合比价大的XML的解析
DOM解析的特点
-一次性将XML全部加载到内存,以树形结构
-好处,可以动态的修改,添加,删除节点
-内存消耗非常大!尤其横向节点越深!
-iOS默认不支持 DOM 解析!
-在 MAC 端,或者服务器端开发,都基本上使用 DOM 解析
-在 iOS 端如果需要使用 DOM 方式解析,可以使用第三方框GData/KissXML(XMPP)
-适合比较小的 XML 文件
-在 MAC 中,苹果提供了一个 NSXML 的类,能够做 DOM 解析,在 iOS 不能使用!
2.网络协议
1>TCP如何防止乱序和丢包
TCP数据包的头格式中有两个概念,Sequence Number是数据包的序号,用来解决网络包乱序(reordering)问题。Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码).
SeqNum的增加是和传输的字节数相关的,TCP传输数据时,A主机第一次传输1440个字节,seq=1,那么第二次时seq = 1441,B拼接数据就是根据seq进行拼接的,seq数字不断累加避免了乱序.B主机收到第一次数据包以后会返回ack = 1441.
A主机收到B的ack = 1441时,就知道第一个数据包B已收到. 如果B没有收到第一次的数据包,那么B再收到A的数据包时,他就会发ack = 1回去,A收到B的回复,发现B没有收到第一次数据包,就会重发第一次数据包,这样就可以防止丢包.
2>描述一下三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据.
3> TCP与UDP的区别:
3.1>基于连接与无连接;
3.2>对系统资源的要求(TCP较多,UDP少);
3.3>UDP程序结构较简单;
3.4>流模式与数据报模式 ;
3.5>TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
4>http和scoket通信的区别
http是客户端用http协议进行请求,发送请求时候需要封装http请求头,并绑定请求的数据,服务器一般有web服务器配合(当然也非绝对)。 http请求方式为客户端主动发起请求,服务器才能给响应,一次请求完毕后则断开连接,以节省资源。服务器不能主动给客户端响应(除非采取http长连接技术)。iPhone主要使用类是NSUrlConnection。
scoket是客户端跟服务器直接使用socket“套接字”进行连接,并没有规定连接后断开,所以客户端和服务器可以保持连接通道,双方都可以主动发送数据。一般在游戏开发或股票开发这种要求即时性很强并且保持发送数据量比较大的场合使用。主要使用类是CFSocketRef。
3.网络传输
1>DNS是如何工作的
DNS是domain name server的简称,每个网络的计算机都有ip,但是不好记,所以用域名替代(如www.baidu.com),在 Internet 上真实在辨识机器的还是 IP,所以当使用者输入Domain Name 后,浏览器必须要先去一台有 Domain Name 和IP 对应资料的主机去查询这台电脑的 IP,而这台被查询的主机,我们称它为 Domain Name Server,简称DNS,例如:当你输入www.pchome.com.tw时,浏览器会将www.pchome.com.tw这个名字传送到离他最近的 DNS Server 去做辨识,如果查到,则会传回这台主机的 IP,进而跟它索取资料,但如果没查到,就会发生类似 DNS NOT FOUND 的情形,所以一旦DNS Server当机,就像是路标完全被毁坏,没有人知道该把资料送到那里
二.网络安全/加密
料送到那里
三.数据存储
1.数据存储技术
1> 数据存储的几种方式
1.1> plist xml
1.2> 偏好设置
1.3> 归档 Document 自定义对象 NSCoding协议
如何使用plist保存视图尺寸 NSValue
2> 沙盒目录结构
2.1> Library Caches Preferences
2.2> Documents
2.3> tmp
2.数据库技术(SQLite&CoreData)
四.Html5/oc&js互调
oc>js:[self.webView stringByEvaluatingJavaScriptFromString:“window.location.href = xxx”];
js>oc: 利用hmtl中js的重定向技术,<Script> window.location.href = www.baidu.com//method:dosomething </Script>
使用方法截取重定向
(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
五.iOS网络框架
1> NSURLConnection和NSURLSession的区别
1.1> 异步请求不需要NSOperation包装
1.2> 支持后台运行的网络任务(后台上传下载)
1.3> 根据每个Session做配置(http header,Cache,Cookie,protocal,Credential),不再在整个App层面共享配置
1.4> 支持网络操作的取消和断点续传(继承系统类,重新main方法)
1.5> 改进了授权机制的处理
项目
1.实用技术
2.知名第三方框架
3.开发技巧
1> description方法
Swift
1> Swift和OC的区别
1.1> Swift没有地址/指针的概念
1.2> 泛型
1.3> 类型严谨 对比oc的动态绑定
6.设计模式
1> 常用的设计模式
代理 观察者 工厂 单例 策略
2> 代理属性的内存策略是什么,为什么?
3> 观察者模式的使用场景
4> 工厂模式(类方法)为什么没有释放对象? autorelease工作原理? arc下还需要手动使用autorelease吗?为什么?什么场景?
5> 手写单例
6> 策略 cell多种响应效果 代理方法
(一)代理模式
应用场景:当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。
优势:解耦合
敏捷原则:开放-封闭原则
实例:tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。
列表row个数delegate
自定义的delegate
(二)观察者模式
应用场景:一般为model层对controller和view进行的通知方式,不关心谁去接收,只负责发布信息。
优势:解耦合
敏捷原则:接口隔离原则,开放-封闭原则
实例:Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。
kvo,键值对改变通知的观察者,平时基本没用过。
(三)MVC模式
应用场景:是一中非常古老的设计模式,通过数据模型,控制器逻辑,视图展示将应用程序进行逻辑划分。
优势:使系统,层次清晰,职责分明,易于维护
敏捷原则:对扩展开放-对修改封闭
实例:model-即数据模型,view-视图展示,controller进行UI展现和数据交互的逻辑控制。
(四)单例模式
应用场景:确保程序运行期某个类,只有一份实例,用于进行资源共享控制。
优势:使用简单,延时求值,易于跨模块
敏捷原则:单一职责原则
实例:[UIApplication sharedApplication]。
注意事项:确保使用者只能通过 getInstance方法才能获得,单例类的唯一实例。
java,C++中使其没有公有构造函数,私有化并覆盖其构造函数。
object c中,重写allocWithZone方法,保证即使用户用 alloc方法直接创建单例类的实例,返回的也只是此单例类的唯一静态变量。
(五)策略模式
应用场景:定义算法族,封装起来,使他们之间可以相互替换。
优势:使算法的变化独立于使用算法的用户
敏捷原则:接口隔离原则;多用组合,少用继承;针对接口编程,而非实现。
实例:排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。
注意事项:1,剥离类中易于变化的行为,通过组合的方式嵌入抽象基类
2,变化的行为抽象基类为,所有可变变化的父类
3,用户类的最终实例,通过注入行为实例的方式,设定易变行为
防止了继承行为方式,导致无关行为污染子类。完成了策略封装和可替换性。
(六)工厂模式
应用场景:工厂方式创建类的实例,多与proxy模式配合,创建可替换代理类。
优势:易于替换,面向抽象编程,application只与抽象工厂和易变类的共性抽象类发生调用关系。
敏捷原则:DIP依赖倒置原则
实例:项目部署环境中依赖多个不同类型的数据库时,需要使用工厂配合proxy完成易用性替换
注意事项:项目初期,软件结构和需求都没有稳定下来时,不建议使用此模式,因为其劣势也很明显,
增 加了代码的复杂度,增加了调用层次,增加了内存负担。所以要注意防止模式的滥用。
六.框架
1.SDWebimage
1> SDWebimage的缓存机制
- UIImageView+WebCache: setImageWithURL:placeholderImage:options: 先显示 placeholderImage ,同时由SDWebImageManager 根据 URL 来在本地查找图片。
- SDWebImageManager: downloadWithURL:delegate:options:userInfo: SDWebImageManager是将UIImageView+WebCache同SDImageCache链接起来的类, SDImageCache: queryDiskCacheForKey:delegate:userInfo:用来从缓存根据CacheKey查找图片是否已经在缓存中
- 如果内存中已经有图片缓存, SDWebImageManager会回调SDImageCacheDelegate : imageCache:didFindImage:forKey:userInfo:
- 而 UIImageView+WebCache 则回调SDWebImageManagerDelegate: webImageManager:didFinishWithImage:来显示图片。
- 如果内存中没有图片缓存,那么生成 NSInvocationOperation 添加到队列,从硬盘查找图片是否已被下载缓存。
- 根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调
- notifyDelegate:
- 如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:进而回调展示图片。
- 如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调
- imageCache:didNotFindImageForKey:userInfo:
- 共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
- 图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
- connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
- connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。
- 图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
- 在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
- imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
- 通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
- 将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。
- 写文件到硬盘在单独 NSInvocationOperation 中完成,避免拖慢主线程。
- 如果是在iOS上运行,SDImageCache 在初始化的时候会注册notification 到 UIApplicationDidReceiveMemoryWarningNotification 以及 UIApplicationWillTerminateNotification,在内存警告的时候清理内存图片缓存,应用结束的时候清理过期图片。
- SDWebImagePrefetcher 可以预先下载图片,方便后续使用。
位运算
NSCache
特点: a> 线程安全的 b> 当内存不足的时候,自动释放 c> 缓存数量和缓存成本
区别NSMutableDictionary
1> 不能也不应该遍历 2> NSCache对key强引用,NSMutableDictionary对key进行copy
2.AFN
1>实现原理
AFN的直接操作对象AFHTTPClient不同于ASI,是一个实现了NSCoding和NSCopying协议的NSObject子类。 AFHTTPClient是一个封装了一系列操作方法的“工具类”,处理请求的操作类是一系列单独的,基于NSOperation封装 的,AFURLConnectionOperation的子类。AFN的示例代码中通过一个静态方法,使用dispatch_once()的方式创建 AFHTTPClient的共享实例,这也是官方建议的使用方法。在创建AFHTTPClient的初始化方法中,创建了OperationQueue并 设置一系列参数默认值。在getPath:parameters:success:failure方法中创建NSURLRequest,以 NSURLRequest对象实例作为参数,创建一个NSOperation,并加入在初始化发方中创建的NSOperationQueue。以上操作都 是在主线程中完成的。在NSOperation的start方法中,以此前创建的NSURLRequest对象为参数创建NSURLConnection 并开启连结。
2> 传递指针 如何使一个方法返回多个返回值
七.项目
3.混编
arc mrc混编
c c++混编
4.加密
八.算法
交换数值的几种方法 中间变量 加减法 异或
二叉树
链表
递归