0 1 1.1 1.2 1.3 1.4 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 2.15 2.16 2.17 2.18 2.19 2.20 Table of Contents Introduction C语⾔部分 static 关键字的作⽤ 堆和栈的区别 c语⾔如何判断两个单向⽆环链表是否相交 引⽤与指针有什么区别 OC语⾔部分 谈谈obj-c的优缺点? Objective-C有多继承吗?没有的话⽤什么代替 Objective-C有私有⽅法吗?私有变量呢? 定义属性时,什么情况使⽤copy、assign、retain 单例模式的书写 类别的作⽤?继承和类别在实现中有何区别? 什么是nsmanagedobject模型? 什么是谓词? C和obj-c如何混⽤ 内存管理问题合集 对象是什么时候被释放的 为什么很多内置的类,如TableView的delegate的属性是assign不是retain 关键字const什么含义? 原⼦(atomic)跟⾮原⼦(non-atomic)属性有什么区别? public_private_protected 常⻅的objective-c的数据类型有哪些,和c的基本类型有什么区别 C++和OC,JAVA和OC之间的区别? id、nil代表什么? nil与NULL的区别? import、include、class区别 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 12.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.35 2.36 2.37 2.38 2.39 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 @property修饰符 你了解的设计模式 ARC是什么 ARC通过什么⽅式帮助开发者管理内存 CAAnimation的层级结构 iOS本地数据存储都有哪⼏种⽅式 深拷⻉和浅拷⻉的理解 什么是序列化和反序列化,可以⽤来做什么? 什么是懒加载 self.跟self->什么区别? objc中的类⽅法和实例⽅法有什么本质区别和联系? iOS中的事件的传递:响应链 block使⽤注意点 类别_继承_拓展 OC协议和JAVA接⼝ 单例的理解和使⽤ KVC和KVO kvo、kvo的使⽤场景 多⼈开发内存泄露的检查 UI部分 描述什么是MVC MVVM frame与bounds __block/weak修饰符的区别 awakeFromNib与viewDidLoad区别 UIViewController的⽣命周期⽅法调⽤顺序 ViewController的loadView、init等⽅法的调⽤ UITableView的执⾏流程是怎么样的 LayoutSubviews何时会被调⽤ 应⽤程序按Home键进⼊后台时的⽣命周期 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 23.11 3.12 3.13 3.14 4 4.1 4.2 5 5.1 5.2 5.3 5.4 5.5 5.6 6 6.1 6.2 6.3 6.4 7 7.1 8 8.1 8.2 8.3 8.4 ViewController的didReceiveMemoryWarning是在什么时候调⽤的?默认的操作 是什么 tableview的性能优化 tableview的重⽤机制 iOS之事件的传递和响应机制 ⽹络部分 http的post与get区别与联系 OAuth授权 多线程部分 线程与进程的区别和联系 对多线程开发的理解 多线程安全 gcd内部怎么实现的 检查内存管理问题的⽅式有哪些? 怎么解决缓存池满的问题(cell) 补充实⽤部分 ide的介绍 coredata iOS6、7、8、9新特性汇总和适配说明 SQLite数据库框架--FMDB 第三⽅框架 SDWebImage 其他 HR⼈事⾯试常⻅问题 pch⽂件的作⽤ ATS 应⽤传输安全(Xcode7之后不能访问⽹络解决⽅案) Xcode 7免证书真机调试 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 3iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 三四⽉⼜到了求职、跳槽的⾼峰期啦!作为iOS的程序员来说,⾯试绝对是不容⼩觑的事 情!今天,⼩舞⼜给⼤家放出⼤福利——iOS⾯试宝典来啦! 本⽂从编程、设计、App Store等各个⽅⾯对iOS程序员在⾯试时可能会遇到的问题进⾏了 筛选与汇总,⼀⽅⾯帮助咱们同学们更系统的复习iOS学过的所有内容,另⼀⽅⾯给⼤家 在寻找iOS程序员⼯作时作为参考,让薪资再涨5K哦! 当然咱们的⾯试宝典也是会有定时的更新,想获取更多有关iOS的⼲货、资料,请假QQ 1641907557 ,⼩舞会给⼤家分享更多狠货哦!当然,咱们的⼤神都在群 131657917 , 想“涨姿势”的⼩伙伴快来加⼊我们吧! iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 4IntroductionC语⾔部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 5C语⾔部分static 关键字的作⽤ 1. 第⼀个作⽤:隐藏。 当我们同时编译多个⽂件时,所有未加static前缀的全局变量和 函数都具有全局可⻅性。 2. static的第⼆个作⽤是保持变量内容的持久。存储在静态数据区的变量会在程序刚开 始运⾏时就完成初始化,也是唯⼀的⼀次初始化。共有两种变量存储在静态存储区: 全局变量和static变量,只不过和全局变量⽐起来,static可以控制变量的可⻅范围, 说到底static还是⽤来隐藏的。 3. static的第三个作⽤是默认初始化为0。其实全局变量也具备这⼀属性,因为全局变量 也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候 这⼀特点可以减少程序员的⼯作量。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 6static 关键字的作⽤堆和栈的区别 管理⽅式: 对于栈来讲,是由编译器⾃动管理,⽆需我们⼿⼯控制; 对于堆来说,释放⼯作由程序员控制,容易产⽣memory leak。 申请⼤⼩: 栈:在Windows下,栈是向低地址扩展的数据结构,是⼀块连续的内存的区域。这句 话的意思是栈顶的地址和栈的最⼤容量是系统预先规定好的,在 WINDOWS下,栈 的⼤⼩是2M(也有的说是1M,总之是⼀个编译时就确定的常数),如果申请的空间 超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较⼩。 堆:堆是向⾼地址扩展的数据结构,是不连续的内存区域。这是由于系统是⽤链表来 存储的空闲内存地址的,⾃然是不连续的,⽽链表的遍历⽅向是由低地址向⾼地址。 堆的⼤⼩受限于计算机系统中有效的虚拟内存。由此可⻅,堆获得的空间⽐较灵活, 也⽐较⼤。 碎⽚问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从⽽造成 ⼤量的碎⽚,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后 出的队列,他们是如此的⼀⼀对应,以⾄于永远都不可能有⼀个内存块从栈中间弹出 分配⽅式:堆都是动态分配的,没有静态分配的堆。栈有2种分配⽅式:静态分配和 动态分配。静态分配是编译器完成的,⽐如局部变量的分配。动态分配由alloca函数 进⾏分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进⾏释放,⽆ 需我们⼿⼯实现。 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供⽀持:分配专⻔ 的寄存器存放栈的地址,压栈出栈都有专⻔的指令执⾏,这就决定了栈的效率⽐较 ⾼。堆则是C/C++函数库提供的,它的机制是很复杂的。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 7堆和栈的区别C语⾔如何判断两个单向⽆环链表是否相交 只需判断两个链表的尾节点地址是否相同,相同则相交,不同则不相交 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 8c语⾔如何判断两个单向⽆环链表是否相交引⽤与指针有什么区别 指针指向⼀块内存,它的内容是所指内存的地址 引⽤是某块内存的别名 1. 指针是⼀个实体,⽽引⽤仅是个别名; 2. 引⽤使⽤时⽆需解引⽤(*),指针需要解引⽤; 3. 引⽤只能在定义时被初始化⼀次,之后不可变;指针可变; 4. 引⽤没有 const,指针有 const; 5. 引⽤不能为空,指针可以为空; 6. “sizeof 引⽤”得到的是所指向的变量(对象)的⼤⼩,⽽“sizeof 指针”得到的是指针 本身(所指向的变量或对象的地址)的⼤⼩; 7. 指针和引⽤的⾃增(++)运算意义不⼀样; 8.从内存分配上看:程序为指针变量分 配内存区域,⽽引⽤不需要分配内存区域。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 9引⽤与指针有什么区别OC语⾔部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 10OC语⾔部分谈谈obj-c的优缺点? 优点: 1. Cateogies 2. 动态识别 3. 指标计算 4. 弹性讯息传递 5. 不是⼀个过度复杂的 C 衍⽣语⾔ 6. Objective-C 与 C++ 可混合编程 缺点: 1. 不⽀援命名空间机制:须在其类别名称加上前缀,时常引致冲突。 2. 不⽀持运算符重载 3. 不⽀持多重继承:只容许对象继承⼀个类别 4.使⽤动态运⾏时类型,所有的⽅法都是 函数调⽤,很多常⻅的编译时性能优化⽅法都不能应⽤于Obj-C(如内联函数、常数 传播、交互式优化、纯量取代与聚集等),性能劣于类似的对象抽象语⾔(如 C++)。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 11谈谈obj-c的优缺点?Objective-C有多继承吗?没有的话⽤什么代替 1. OC是单继承,没有多继承 2. 有时可以⽤分类和协议来代替多继承 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 12Objective-C有多继承吗?没有的话⽤什么代替Objective-C有私有⽅法吗?私有变量呢? 1. OC没有类似 @private 的修饰词来修饰⽅法,只要写在 .h ⽂件中,就是公共⽅法 2. 可以使⽤类扩展(Extension)来增加私有⽅法和私有变量 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 13Objective-C有私有⽅法吗?私有变量呢?定义属性时,什么情况使⽤copy、assign、retain? 1. copy : NSString 、 Block 等类型 1. assign :⾮OC对象类型, 基本数据类型(两个对象相互引⽤的时候,⼀端 ⽤ retain , ⼀端⽤ assign ) 2. retain :OC对象类型 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 14定义属性时,什么情况使⽤copy、assign、retain单例模式的书写 ARC // 定义⼀个静态变量,在程序运⾏过程中只有1份 static id instance; - ( instancetype ) init { static id obj = nil; //onceToken初始为0 static dispatch_once_t onceToken; // 确保只执⾏⼀次初始化代码 dispatch_once(&onceToken, ^{ //执⾏过后, onceToken变为-1,block内代码不再执⾏ if ((obj = [super init])) { // 加载资源 NSLog(@"加载资源"); } }); return obj; } // 重写这个⽅法控制内存只分配⼀次 +(instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; // ⾥⾯的代码只会执⾏1次 dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); // 返回对象 return instance; } // 确保复制的对象还是同⼀个 - (id)copyWithZone:(NSZone *)zone { iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 15单例模式的书写 return self; } // 全局访问点 + (instancetype)sharedAudioTool { return [[self alloc] init]; } OC 中的单例 + (instancetype)sharedManager { static id instance; static dispatch_once_t onceToken; NSLog(@"%ld", onceToken); dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance; } 根据OC单例 改写成 Swift 中的单例 static var instance: Tools? static var token: dispatch_once_t = 0 class func sharedInstance() -> Tools { dispatch_once(&token) { () -> Void in instance = Tools() } return instance! } OC调⽤swift,需要#import "单例-Swift.h",其中单例为Product Name 在 Swift 中 let 本身就 是线程安全的 改进过的单例代码 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 16单例模式的书写static let instance = Tools() class func sharedInstance() -> Tools { return instance } 单例其实还可以更简单 最终形态 static let sharedTools = Tools() iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 17单例模式的书写类别的作⽤?继承和类别在实现中有何区别? category 可以在不获悉,不改变原来代码的情况下往⾥⾯添加新的⽅法,只能添加,不能 删除修改,并且如果类别和原来类中的⽅法产⽣名称冲突,则类别将覆盖原来的⽅法,因 为类别具有 更⾼的优先级。 类别主要有3个作⽤: 1).将类的实现分散到多个不同⽂件或多个不同框架中。 2).创建对私有⽅法的前向引⽤。 3).向对象添加⾮正式协议。 继承可以增加,修改或者删除⽅法,并且可以增加属性。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 18类别的作⽤?继承和类别在实现中有何区别?什么是NSManagedObject模型? NSManagedObject 是 NSObject 的⼦类 ,也是coredata的重要组成部分,它是⼀个通⽤的类, 实现了core data 模型层所需的基本功能,⽤户可通过⼦类化 NSManagedObject ,建⽴⾃⼰ 的 数据模型。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 19什么是nsmanagedobject模型?什么是谓词? 谓词是通过NSPredicate,是通过给定的逻辑条件作为约束条件,完成对数据的筛选。 predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n]; a = [customers filteredArrayUsingPredicate:predicate]; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 20什么是谓词?C和obj-c 如何混⽤ 1. obj-c的编译器处理后缀为m的⽂件时,可以识别obj-c和c的代码,处理mm⽂件可以 识别obj-c,c,c++代码,但cpp⽂件必须只能⽤c/c++代码,⽽且cpp⽂件include的头⽂ 件中,也不能出现 obj-c的代码,因为cpp只是cpp 2. 在mm⽂件中混⽤cpp直接使⽤即可,所以obj-c混cpp不是问题 3. 在cpp中混⽤obj-c其实就是使⽤obj-c编写的模块是我们想要的。 如果模块以类实现,那么要按照cpp class的标准写类的定义,头⽂件中不能出现obj-c的 东⻄,包括#import cocoa的。实现⽂件中,即类的实现代码中可以使⽤obj-c的东⻄,可 以import,只是后 缀是mm。 如果模块以函数实现,那么头⽂件要按c的格式声明函数,实现⽂件中,c++函数内部可以 ⽤obj-c,但后缀还是mm或m。 总结:只要cpp⽂件和cpp include的⽂件中不包含obj-c的东⻄就可以⽤了,cpp混⽤obj-c 的关键是使⽤接⼝,⽽不能直接使⽤ 实现代 码,实际上cpp混⽤的是obj-c编译后的o⽂ 件,这个东⻄其实是⽆差别的,所以可以⽤。obj-c的编译器⽀持cpp iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 21C和obj-c如何混⽤内存管理问题合集 什么是ios内存管理? 就是在对象不再被使⽤的时候,把它即时的从内存中清除掉 为什么要使⽤内存管理? 严格的内存管理,能够是我们的应⽤程在性能上有很⼤的提⾼ 如果忽略内存管理,可能导致应⽤占⽤内存过⾼,导致程序崩溃 系统判断⼀个对象是否要被销毁的依据是什么? 每个对象创建出来的时候,都有⼀个retainCount属性,默认值是1,当retainCount = 0的 时候,系统就会将该对像销毁 如何使对象的retainCount 值增加? 调⽤retain 对象⽅法 如何使对象的retainCount 值减少? 调⽤release 对象⽅法 如何判断对象已经被销毁了? 从写NSObject提供的,dealloc⽅法,当对象即将被销毁的时候,默认会调⽤该⽅法 dealloc⽅法中⼀定要调⽤[super dealloc]⽅法 内存管理原则是什么? 只要是出现new,alloc,retain,就要配对出现release操作,或者autorelease操作 单个对象内存管理 问题 什么是野指针? 对象的retainCount已经为0,保存了对象指针地址的变量就是野指针 使⽤野指针会有什么问题? 使⽤野指针调⽤对象的⽅法,会导致野指针异常,导致程序直接崩溃 什么是僵⼫对象? iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 22内存管理问题合集retainCount = 0的对象被称之为僵⼫对象,也就是不能够在访问的对象 如何防⽌出现野指针操作? 通常在调⽤完release ⽅法后,会把保存了对象指针地址的变量清空,赋值为nil 在oc中 没有空指针异常,所以使⽤[nil retain]调⽤⽅法不会导致异常的发⽣ 什么是内存泄漏? 已经不在使⽤的对象,没有正确的释放掉,⼀直驻留在内存中,我们就说是内存泄漏 内存泄漏有⼏种情况? 1.没有配对释放,不符合内存管理原则 2.对象提前赋值为nil或者 清空,导致release⽅法没有起作⽤ 当对象的retainCount = 0 时 能否调⽤ retain⽅法使对象复活? 已经被释放的对象是⽆法在复活的 关于内存我们主要研究的问题是什么? 野指针 内存泄露 多个对象内存管理 问题 对象与对象之间存在⼏种关系? 继承关系 组合关系 对象作为⽅法参数传递 对象的组合关系中,如何确保作为成员变量的对象,不会被提前释放? 重写set⽅法,在set⽅法中,retain该对像,使其retainCount值增加 1 组合关系导致内存泄漏的原因是什么? 在set⽅法中,retain了该对象,但是并没有配对释放 作为成员变量的对象,应该在那⾥配对释放? 在dealloc函数中释放 set⽅法内存管理 问题 在对象的组合关系中,导致内存泄漏有⼏种情况? set⽅法中没有retain对象 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 23内存管理问题合集没有release掉旧的对象 没有判断向set⽅法中传⼊的是否是同⼀个对象 该如何正确的重写set⽅法? 先判断是否是同⼀个对象 release⼀次旧的对象 retain新的对象 内存管理@property参数 问题 @property参数分为⼏类? 与set⽅法内存管理相关的参数 是否要⽣成set⽅法相关 多线程相关 set和get⽅法的名称相关 ⾃动释放池 问题 什么是⾃动释放池? ⾃动释放池是⽤来存储多个对象类型的指针变量 ⾃动释放池对池内对象的作⽤? 被存⼊到⾃动释放池内的对象,当⾃动释放池被销毁时,会对池内的对象全部做⼀次 release操作 对象如何放⼊到⾃动释放池中? 当你确定要将对象放⼊到池中的时候,只需要调⽤对象的 autorelease 对象⽅法就可 以把对象放⼊到⾃动释放池中 如何创建⾃动释放池? 对象在⾃动释放池内部调⽤autorelease ⽅法 ⾃动释放池能否嵌套使⽤? 能 ⾃动释放池何时被销毁? 在autorelease 的 '}' 执⾏完后 多次调⽤对象的autorelease⽅法会导致什么问题? iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 24内存管理问题合集多次将地址存到⾃动释放池中,导致野指针异常 ⾃动释放池作⽤ 将对象与⾃动释放池建⽴关系,池⼦内调⽤autorelease ⽅法,在⾃动释放池销毁时销毁 对象,延迟release销毁时间 ⾃动释放池应⽤ 问题 实际开发中⼀般如何使⽤autorlease 就是在⽅法中创建新的对象并且需要返回的时候 快速创建⼀个类⽅法 ARC机制 问题 什么是ARC机制 ⾃动引⽤计数,不需要程序员关⼼,对象的retain,与release操作 ARC机制中,系统判断对象是否被销毁的依据是什么? 指向对象的强指针是否被销毁 ARC机制的本质是什么? 对releaseCount的计算,创建对象 +1, 清空指针 -1,或者越到autoreleasepool的⼤括号 -1 ARC的⽬的 是让程序员不在关⼼对象的retainCount 如何解决ARC机制下类的相互引⽤问题? 在.h⽂件中使⽤@class关键字声明⼀个类,两端不能都⽤强指针 ⼀端⽤strong,⼀端⽤ weak iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 25内存管理问题合集对象是什么时候被释放的 每个对象都有⼀个引⽤计数器,每个新对象的计数器是1,当对象的计数器减为0时,就会 被销毁 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 26对象是什么时候被释放的为什么很多内置的类,如TableView的delegate的属性是 assign不是retain 1. tableView的代理⼀般都是它所属的控制器,控制器会对它内部的view做⼀ 次 retain 操作 2. 假设tableView也对代理(控制器)做⼀次 retain 操作,那么就出现循环 retain 问题 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 27为什么很多内置的类,如TableView的delegate的属性是assign不是retain关键字const什么含义? const int a; int const a; const int *a; int const *a; int * const a; int const * const a; 1. 前两个的作⽤是⼀样:a 是⼀个常整型数 1. 第三、四个意味着 a 是⼀个指向常整型数的指针(整型数是不可修改的,但指针可以) 1. 第五个的意思:a 是⼀个指向整型数的常指针(指针指向的整型数是可以修改的,但指 针是不可修改的) 1. 最后⼀个意味着:a 是⼀个指向常整型数的常指针(指针指向的整型数是不可修改的, 同时指针也是不可修改的) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 28关键字const什么含义?原⼦(atomic)跟⾮原⼦(non-atomic)属性有什么区别? 1. atomic提供多线程安全。是防⽌在写未完成的时候被另外⼀个线程读取,造成数据错 误 2. non-atomic:在⾃⼰管理内存的环境中,解析的访问器保留并⾃动释放返回的值,如果 指定了 nonatomic ,那么访问器只是简单地返回这个值。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 29原⼦(atomic)跟⾮原⼦(non-atomic)属性有什么区别?public/private/protected的具体区别 public公共,加上这个修饰的类或属性,可以在同⼀个包或者别的包⾥⾯访问 private私有的,加上这个修饰的类或属性,只能在同类⾥访问,同包和别的包不能访 问 protected保护,加上这个修饰的类或属性,只能在类和同包访问,别的包不能访问 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 30public_private_protected常⻅的objective-c的数据类型有哪些,和c的基本类型有什么 区别 常⻅的object-c的数据类型 有 NSInteger 、 CGFloat 、 NSString 、 NSNumber 、 NSArray 、 NSData , NSInteger 会根据系 统是32位还是64位来决定是本身是 int 还是 long , CGFloat会根据系统是32位还是64位来 决定是本身是 float 还是 double , NSString 、 NSNumber 、 NSArray 、 NSData 都是指针类型 的对象,在堆中分配空间,⽽c语⾔中的 char , ... [ ] 等都是在栈中分配空间 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 31常⻅的objective-c的数据类型有哪些,和c的基本类型有什么区别C++和OC,JAVA和OC之间的区别? C++是功能强⼤,丰富的⾯向对象编程语⾔,具有私有、公有、保护权限的三种成员 变量和成员⽅法,具有私有、公有、保护三种继承⽅式,具有重写,重载,虚函数, 虚基类等多态⽅式,通过虚基类实现代理回调。⾃定义类可以没有⽗类。另外具备向 量,模板,友元,重载运算符等多种独特语法 OC是针对mac OS和iOS设备应⽤程序开发的专属编程语⾔,采⽤动态继承,消息⽅ 法机制,没有真正的重写机制,没有私有⽅法,继承⽅式为公有,具备协议,类别, Block等独有的语法,万⽤⽗类为NSObject JAVA是⽼牌的⾯向对象语⾔,编写的程序在JAVA虚拟机上运⾏,真正实现了⼀次编 译到处运⾏,具有复杂的内存回收机制,单继承模式,接⼝语法类似OC的协议 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 32C++和OC,JAVA和OC之间的区别?id、nil代表什么? 1. id类型的指针可以指向任何OC对象 1. nil代表空值(空指针的值, 0) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 33id、nil代表什么?nil与NULL的区别? 从Objective-C语⾔的官⽅说法上看 nil 表示指向对象的指针即所谓对象的引⽤为空 NULL 表示指向基础类型变量即C语⾔变量的指针为空 如果在⾮ARC程序的编写过程中,两个空是可以互换的,但是在ARC环境下,普通指针和 对象引⽤被严格限制,不能交换使⽤,因此也应尽量不互换使⽤ nil 与 NULL iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 34nil与NULL的区别?#import 和 #include的区别,@class代表什么? @class ⼀般⽤于头⽂件中需要声明该类的某个实例变量的时候⽤到,在 .m ⽂件中 还 是需要使⽤ #import 和 #import ⽐起来, #include 的好处就是不会引起重复包含 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 35import、include、class区别###属性 readwrite, readonly, assign, retain, copy, nonatomic 各是什么作⽤,在哪种情况 下⽤? assign: 指定setter⽅法⽤简单的赋值,这是默认操作。你可以对标量类型(如int)使 ⽤这个属性。你可以想象⼀个float,它不是⼀个对象,所以它不能retain、copy。 retain/strong:指定retain应该在后⾯的对象上调⽤,前⼀个值发送⼀条release消 息。你可以想象⼀个NSString实例,它是⼀个对象,⽽且你可以想要retain它,ARC 中使⽤Strong。 copy:指定应该使⽤对象的副本(深度复制),前⼀个值发送⼀条release消息。基 本上像retain,但是没有增加引⽤计数,是分配⼀块新的内存来放置它。 readonly:默认属性,将⽣成不带额外参数的getter和setter⽅法(setter⽅法只有⼀ 个参数)。 atomic:对于对象的默认属性,就是setter/getter⽣成的⽅法是⼀个原⼦操作。如果 有多个线程同时调⽤setter的话,不会出现某⼀个线程执⾏setter全部语句之前,另⼀ 个线程开始执⾏setter的情况,相当于⽅法头尾加了锁⼀样。 nonatomic: 不保证setter/getter的原⼦性,多线程情况下数据可能会有问题。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 36@property修饰符你了解的设计模式 MVC设计模式 单例模式 代理模式 观察者模式 ⼯⼚模式 适配器模式 简单介绍设计模式: 模型视图控制器(MVC)。控制器负责⾏为,模型提供数据源,视图显示UI。模型和视 图之间尽量不要直接打交道,他们之间的交互应该通过控制器来进⾏,控制器充当着 桥梁的作⽤。这样设计的⽬的是使不同功能的类之间尽量解耦,以利于程序的扩展。 代理模式 委托代理(degegate),顾名思义,把某个对象要做的事情委托给别的对 象去做。那么别的对象就是这个对象的代理,代替它来打理要做的事。反映到程序 中,⾸先要明确⼀个对象的委托⽅是哪个对象,委托所做的内容是什么。这⾥所做的 内容是靠协议中的⽅法来实现,⽅法分两种:必需实现(@required)的⽅法和根据情 况选择实现(@optional)的⽅法。 举个例⼦:你是房屋租赁中介,某个房东和你签订 协议,请你替他把房⼦出租出去。这时,你就是房东的代理,你必须实现的⽅法是把 屋⼦出租出去,选择实现的⽅法是装修、添置家具、打隔断等(依据协议⽽定)。 观察者模式 通知模式是观察者模式的⼀种。a对象在通知中⼼注册了观察者之后,b对象发出 通知⼴播,a对象收到通知后就知道去做具体的事。观察者可以是⼀个或多个, 也可以没有。举个例⼦:微博切换帐号后会发出⼀个通知,让多个界⾯重新刷新 数据。 Key-Value-Observer(KVO)模式也是观察者模式的⼀种。KVO的机制为:当 指定的被观察对象的属性被修改的时候,KVO都会⾃动的去通知相应的观察者。 举个例⼦,在控制器⾥通过addObserver:forKeyPath:options:context:注册⼀个 数据源观察者,当数据源⾥的数据发⽣变化时,通过willChangeValueForKey:和 didChangeValueForKey:这⼀对⽅法发出⼴播,控制器收到⼴播后就可以利⽤新 的数据来刷新界⾯。 单例模式 通过单例模式可以保证系统中⼀个类只有⼀个实例⽽且该实例易于外界访 问,从⽽⽅便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只 能存在⼀个,单例模式是最好的解决⽅案。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 37你了解的设计模式(⼀)代理模式 应⽤场景:当⼀个类的某些功能需要由别的类来实现,但是⼜不确定具体会是哪个类实 现。 优势:解耦合 敏捷原则:开放-封闭原则 实例: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,⽤户类的最终实例,通过注⼊⾏为实例 的⽅式,设定易变⾏为 防⽌了继承⾏为⽅式,导致⽆关⾏为污染⼦类。完成了策略封装 和可替换性。 (六)⼯⼚模式 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 38你了解的设计模式应⽤场景:⼯⼚⽅式创建类的实例,多与proxy模式配合,创建可替换代理类。 优势:易 于替换,⾯向抽象编程,application只与抽象⼯⼚和易变类的共性抽象类发⽣调⽤关系。 敏捷原则:DIP依赖倒置原则 实例:项⽬部署环境中依赖多个不同类型的数据库时,需要 使⽤⼯⼚配合proxy完成易⽤性替换 注意事项:项⽬初期,软件结构和需求都没有稳定下 来时,不建议使⽤此模式,因为其劣势也很明显, 增 加了代码的复杂度,增加了调⽤层 次,增加了内存负担。所以要注意防⽌模式的滥⽤。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 39你了解的设计模式ARC是什么 ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说, 就是代码中⾃动加⼊了 retain/release ,原先需要⼿动添加的⽤来处理内存管理的引⽤计 数的代码可以⾃动地由编译器完成了。 该机能在 iOS 5/ Mac OS X 10.7 开始导⼊,利⽤ Xcode4.2 可以使⽤该机能。简单地理解 ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,⾃动⽣成实例的引⽤计 数管理部分代码。有⼀点,ARC并不是GC,它只是⼀种代码静态分析(Static Analyzer)⼯具。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 40ARC是什么ARC通过什么⽅式帮助开发者管理内存? 编译时根据代码上下⽂,插⼊ retain/release iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 41ARC通过什么⽅式帮助开发者管理内存CAAnimation的层级结构 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 42CAAnimation的层级结构iOS本地数据存储都有哪⼏种⽅式 NSKeyedArchiver NSUserDefaults Write写⼊⽅式 SQLite3 什么情况下使⽤什么样的数据存储? 1. NSKeyedArchiver:采⽤归档的形式来保存数据,数据对象需要遵守NSCoding协 议,对象对应的类必须提供encodeWithCoder:和initWithCoder:⽅法。缺点:只能⼀ 次性归档保存以及⼀次性解压。所以只能针对⼩量数据,对数据操作⽐较笨拙,如果 想改动数据的某⼀⼩部分,需要解压或归档整个数据。 2. NSUserDefaults:⽤来保存应⽤程序设置和属性、⽤户保存的数据。⽤户再次打开程 序或开机后这些数据仍然存在。NSUserDefaults可以存储的数据类型包括: NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。缺点:如果 要存储其他类型,需要转换为前⾯的类型,才能⽤NSUserDefaults存储。 3. Write写⼊⽅式:永久保存在磁盘中。第⼀步:获得⽂件即将保存的路径:第⼆步: ⽣成在该路径下的⽂件:第三步:往⽂件中写⼊数据:最后:从⽂件中读出数据 1. SQLite:采⽤SQLite数据库来存储数据。SQLite作为⼀中⼩型数据库,应⽤ios中, 跟前三种保存⽅式相⽐,相对⽐较复杂⼀些。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 43iOS本地数据存储都有哪⼏种⽅式深拷⻉和浅拷⻉的理解 浅拷⻉:只复制指向对象的指针,⽽不复制引⽤对象本身。 深拷⻉:复制引⽤对象本身。 意思就是说我有个A对象,复制⼀份后得到A_copy对象后,对于浅复制来说,A和A_copy 指向的是同⼀个内存资源,复制的只不过是是⼀个指针,对象本身资源 还是只有⼀份, 那如果我们对A_copy执⾏了修改操作,那么发现A引⽤的对象同样被修改,这其实违背了 我们复制拷⻉的⼀个思想。深复制就好理解了,内存中存在了 两份独⽴对象本身。 ⽤⽹上⼀哥们通俗的话将就是: 浅复制好⽐你和你的影⼦,你完蛋,你的影⼦也完 蛋 深复制好⽐你和你的克隆⼈,你完蛋,你的克隆⼈还活着。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 44深拷⻉和浅拷⻉的理解什么是序列化和反序列化,可以⽤来做什么? 序列化是把对象转化成字节序列的过程 反序列化是把字节序列恢复成对象 将对象写到⽂件或者数据库⾥,并且能读取出来 如何在OC中实现复杂对象的存储? 遵循NSCoding协议 实现复杂对象的存储 实现该协议后可以对其进⾏打包或解包,转化成 NSData iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 45什么是序列化和反序列化,可以⽤来做什么?什么是懒加载 懒汉模式,只在⽤到的时候才去初始化,也可以理解成延时加载,⼀般懒加载写在getter⽅ 法中。我觉得最好也最简单的⼀个列⼦就是tableView中图⽚的加载显示了。⼀个延时 载,避免内存过⾼,⼀个异步加载,避免线程堵塞。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 46什么是懒加载self.跟self->什么区别? 1. self. 是调⽤ get ⽅法或者 set ⽅法 2. self 是当前本身,是⼀个指向当前对象的指针 3. self-> 是直接访问成员变量 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 47self.跟self->什么区别?objc中的类⽅法和实例⽅法有什么本质区别和联系? 类⽅法: 类⽅法是属于类对象的 类⽅法只能通过类对象调⽤ 类⽅法中的self是类对象 类⽅法可以调⽤其他的类⽅法 类⽅法中不能访问成员变量 类⽅法中不定直接调⽤对象⽅法 实例⽅法: 实例⽅法是属于实例对象的 实例⽅法只能通过实例对象调⽤ 实例⽅法中的self是实例对象 实例⽅法中可以访问成员变量 实例⽅法中直接调⽤实例⽅法 实例⽅法中也可以调⽤类⽅法(通过类名) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 48objc中的类⽅法和实例⽅法有什么本质区别和联系?iOS中的事件的传递:响应链 事件沿着⼀个指定的路径传递直到它遇⻅可以处理它的对象。 ⾸先⼀个UIApplication 对 象从队列顶部获取⼀个事件并分发(dispatches)它以便处理。 通常,它把事件传递给应⽤ 程序的关键窗⼝对象,该对象把事件传递给⼀个初始对象来处理。 初始对象取决于事件 的类型。 触摸事件。 对于触摸事件,窗⼝对象⾸先尝试把事件传递给触摸发⽣的视图。那个视图 被称为hit-test(点击测试)视图。 寻找hit-test视图的过程被称为hit-testing, 参⻅ “Hit- Testing Returns the View Where a Touch Occurred.” 运动和远程控制事件。 对于这些事件,窗⼝对象把shaking-motion(摇晃运动)或远程控制 事件传递给第⼀响应者来处理。第⼀响应者请参⻅ “The Responder Chain Is Made Up of Responder Objects.” iOS 使⽤hit-testing来找到事件发⽣的视图。 Hit-testing包括检查触摸事件是否发⽣在任何 相关视图对象的范围内, 如果是,则递归地检查所有视图的⼦视图。在视图层次中的最 底层视图,如果它包含了触摸点,那么它就是hit-test视图。等 iOS决定了hit-test视图之 后,它把触摸事件传递给该视图以便处理。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 49iOS中的事件的传递:响应链block使⽤注意点 1. block的内存管理(注意循环引⽤,默认在栈中(不需要内存管理),通过copy就在在堆中, 就要注意内存管理) 2. 防⽌循环retian ⾮ARC(MRC):__block ARC:weak\unsafe_unretained iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 50block使⽤注意点类别的作⽤? 类别主要有3个作⽤: 1. 将类的实现分散到多个不同⽂件或多个不同框架中。 2. 创建对私有⽅法的前向引⽤。 3. 向对象添加⾮正式协议。 继承和类别在实现中有何区别? 分类 可以在不获悉,不改变原来代码的情况下往⾥⾯添加新的⽅法,只能添加,不 能删除修改。 并且如果类别和原来类中的⽅法产⽣名称冲突,则类别将覆盖原来的 ⽅法,因为类别具有更⾼的优先级。 继承 可以增加,修改或者删除⽅法,并且可以增加属性。 类别和类扩展的区别? category和extensions的不同在于 后者可以添加属性。另外后者添加的⽅法是必须要实现 的。 extensions可以认为是⼀个私有的Category。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 51类别_继承_拓展obc中的协议和java中的接⼝概念有何不同? OC中的代理有2层含义,官⽅定义为 formal和informal protocol。前者和Java接⼝⼀ 样。 informal protocol中的⽅法属于设计模式考虑范畴,不是必须实现的,但是如果有实 现,就会改变类的属性。 其实关于正式协议,类别和⾮正式协议我很早前学习的时候⼤致看过,也写在了学习 教程⾥ “⾮正式协议概念其实就是类别的另⼀种表达⽅式“这⾥有⼀些你可能希望实现 的⽅法,你可以使⽤他们更好的完成⼯作”。 这个意思是,这些是可选的。⽐如我⻔ 要⼀个更好的⽅法,我们就会申明⼀个这样的类别去实现。然后你在后期可以直接使 ⽤这些更好的⽅法。 这么看,总觉得类别这玩意⼉有点像协议的可选协议。" 现在来看,其实protocal已经开始 对两者都统⼀和规范起来操作,因为资料中说“⾮正式协议使⽤interface修饰“ 现在我们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 52OC协议和JAVA接⼝你单例怎么理解怎么⽤的? Singleton Pattern 单例设计模式,通过单例模式可以保证系统中⼀个类只有⼀个实例⽽且 该实例易于外界访问,从⽽⽅便对实例个数的控制并节约系统资源。如果希望在系统中某 个类的对象只能存在⼀个,单例模式是最好的解决⽅案。类只能有⼀个实例,⽽且必须从 ⼀个为⼈熟知的访问点对其进⾏访问,⽐如⼯⼚⽅法。这个唯⼀的实例只能通过⼦类化进 ⾏扩展,⽽且扩展的对象不会破坏客户端代码。 例如, UIApplication 的 sharedApplication ⽅法,任何时候都会返回⼀个当前应⽤程序 的 UIApplication 实例。在程序中,我需要⼀系列的对象,他们每⼀个内部都包含有⼀组变 量和功能,是静态的,⽽且整个程序都只需要拥有⼀个该类的对象。 例如: 1. 控制程序执⾏的命令器; 2. 管理数据库; 3. ⾳效控制; 4. ⽂件处理 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 53单例的理解和使⽤KVC和KVO KVC 熟悉oc语法的同学也许都会懂得这么⼀点:在oc中,类的成员变量或是⽅法是没有绝对私 有的。 私有⽅法直接通过类实例⽆法访问,但可以借助oc的“编译运⾏时”机制,也即“瞎⼦摸 ⿊”机制(个⼈理解:只要确定了该类有⽅法A,管你是私有共 有,我 ⽤ performSelector 函数就能调⽤你),说到这,也许有同学会⾃然想起,那私有变量如何 去访问呢?貌似以前还真没这样搞过,然⽽现实是 可以的,只不过⼀般我们把变量设为 类的私有变量后是不希望⾃⼰或是其他⼈再去访问的,不然我只能说你⾃⼰⼜在找贱了。 好吧,⾔归正传,这篇⽂章主要是想介绍下oc中的KVC、KVO、KVB的实现机制,当然跟 我上⾯说的那些肯定是有关系的啦。。 1. KVC: key-value coding(键值编码) 它 是⼀种使⽤字符串标识符,间接访问对象属性的机制,它是很多技术的基础。主要的 ⽅法就两对⽅法: ( setValue:forKey , valueForKey )、 setValue:forKeyPath , valueForKeyPath ); 这个东 ⻄有 什么作⽤呢,我先不说原理,先说怎么⽤,例⼦如下: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 54KVC和KVO@interface A { NSString* foo; } ... // 其它代码 @end @interface B { NSString* bar; A* myA; } ... // 其它代码 @end @implementation B ... // 假设 A 类型的对象 a,B 类型的对象 b A* a = ...; B* b = ...; NSString* s1 = [a valueForKey:@"foo"]; // 正确 NSString* s2 = [b valueForKey:@"bar"]; // 正确 NSString* s3 = [b valueForKey:@"myA"]; // 正确 NSString* s4 = [b valueForKeyPath:@"myA.foo"]; // 正确 NSString* s5 = [b valueForKey:@"myA.foo"]; // 错误 NSString* s6 = [b valueForKeyPath:@"bar"]; // 正确 ... @end 其实上⾯说的那两对⽅法使⽤上基本是⼀样的,只是valueForKeyPath的值是⼀个路径 (路径之间以点号 . 分割),⽐如数据成员就是对象⾃⼰,寻值过程就会向下深⼊下去。 注意,这⾥的数据成员的名字都是使⽤的字符串的形式。这种使⽤⽅法的最好的⽤处在于 将数据(名字)绑定到⼀些触发器(尤其是⽅法调⽤)上, 例如键值对观察(Key-Value Observing, KVO)等。 上述代码说明了类的成员变量也可以使⽤基类NSObject的那两对⽅法去访问,不⼀定直 接通过类实例访问,但是这种⽅式还是有⼀定的⻛险,具体危 险情况请参考这个: http://www.devbean.info/2011/04/from_cpp_to_objc_20/ 然后我再说下原理,是俺Copy过来的,⼤家观赏下: > KVC运⽤了⼀个isa- swizzling技 术。isa-swizzling就是类型混合指针机制。KVC主要通过isa- swizzling,来实现其内部查 找定位的。 isa指针,如其名称所指,(就是is a kind of的意思),指向维护分发表的对 象的类。该分发表实际上包含了指向实现类中的⽅法的指针,和其它数据。 ⽐如说如下的⼀⾏KVC的代码: [site setValue:@"sitename" forKey:@"name"]; 就会被编译器处理成: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 55KVC和KVOSEL sel = sel_get_uid ("setValue:forKey:"); IMP method = objc_msg_lookup (site->isa,sel); method(site, sel, @"sitename", @"name"); ⾸先介绍两个基本概念: SEL数据类型:它是编译器运⾏Objective-C⾥的⽅法的环境参数。 IMP数据 类型:他其实就是⼀个编译器内部实现时候的函数指针。当Objective-C编 译器去处理实现⼀个⽅法的时候,就会指向⼀个IMP对象,这个对象是C语⾔表述的 类型(事实上,在Objec+tive-C的编译器处理的时候,基本上都是C语⾔的)。 这下KVC内部的实现就很清楚的清楚了:⼀个对象在调⽤setValue的时候, 1. ⾸先根据⽅法名找到运⾏⽅法的时候所需要的环境参 数。 2. 他会从⾃⼰isa指针结合环境参数,找到具体的⽅法实现的接⼝。 3. 再直接查找得来的具体的⽅法实现。 KVO: key-value observing(键值监听)与KVB: key-value Binding(键值绑定) 这两个机制是结合起来使⽤的,分别说下, Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通 知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会⾃动的去通知相应的观 察者。 KVO的优点 当 有属性改变,KVO会提供⾃动的消息通知。这样的架构有很多好处。 ⾸先,开发⼈员不需要⾃⼰去实现这样的⽅案:每次属性改变了就发送消息通知。这 是KVO 机制提供的最⼤的优点。因为这个⽅案已经被明确定义,获得框架级⽀持, 可以⽅便地采⽤。开发⼈员不需要添加任何代码,不需要设计⾃⼰的观察者模型,直 接可 以在⼯程⾥使⽤。其次,KVO的架构⾮常的强⼤,可以很容易的⽀持多个观察 者观察同⼀个属性,以及相关的值。 KVB实现的两个基本⽅法 为对象添加观察者OBserver addObserver:forKeyPath:options:context: 观察者OBserver收到信息的处理函数 observeValueForKeyPath:ofObject:change:context: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 56KVC和KVOKVO和KVB最明显的使⽤场景就是在⼀些界⾯实时显示⾏很强的地⽅,⽐如股票⾛向、售 票余额等,这种⽅式免去了我们⾃⼰操作通知的麻烦,想到这,我发现当初点⾦和91市场 中下载⻚⾯进度的显示也完全可以采⽤这种⽅式。 原英⽂链接请点我 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 57KVC和KVOKVO、KVO的使⽤场景 键值对编码意思是,能够通过数据成员的名字来访问到它的值。这种语法很类似于关联数 组(在 Cocoa 中就是 NSDictionary),数据成员的名字就是这⾥的键。 KVC使⽤场景: 字典转模型的时候使⽤; [model setValuesForKeysWithDictionary:dict] *利⽤运⾏时和KVC进⾏快速的归档和解档 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 58kvo、kvo的使⽤场景 @implementation MyModel //解档 - (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { unsigned int count = 0; //获取类中所有成员变量名 Ivar *ivar = class_copyIvarList([MyModel class], &count); for (int i = 0; iAnalyze 进⾏内存泄露 的检查和静态分析 2. 为了避免不必要的麻烦,多⼈开发尽量使⽤ARC进⾏开发 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 61多⼈开发内存泄露的检查UI部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 62UI部分描述什么是MVC MVC是⼀种架构模式,它是苹果⾮常热衷的⼀种架构模式 M: model 模型 保存所有应⽤程序⾥要使⽤的数据,⽐如⼀款太空⼤战游戏,模型 要负责保存⻜船的⼤⼩、⻜⾏速度、位置信息、装载了多少只枪等等这些信息。并且 要处理数据之间的逻辑 ⽐如⻜船要打中敌机多少次能把敌机击落 模型只是负责记录 数据,跟数据的显示是没关系的,数据的显示是控制器跟视图的任务 C: controller 控制器 负责控制视图如何去显示模型⾥要显示的数据 它要负责把模型 ⾥的数据传输给视图(控制器是通过视图控制器的【⽣命周期】来控制视图变化的) V:view 视图 视图就是视图控制器的⼩跟班,它的任务就是负责显示视图,完全听命 于视图控制器,视图控制器让视图做什么视图就做什么 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 63描述什么是MVC最近有个MVVM模式⾮常⽕热, 相信它的出现是为了模块化iOS开发, 其实在我看来,它始终 还是MVC模式, 只是⼀个变种罢了 .(当然有⼈⽤到了响应式编程的思路颠覆了常规 , 但我 们今天把讨论点集中于代码的设计模式) . 与其专注于说明 MVVM 的来历,不如让我们看⼀个典型的 iOS 是如何构建的,并从那⾥ 了解MVVM: Typical Model-View-Controller setup 我们看到的是⼀个典型的 MVC设置。Model呈现数据,View呈现⽤户界⾯,⽽ View Controller调节它两者之间的交互。 稍微考虑⼀下,虽然View 和 View Controller是技术上 不同的组件,但它们⼏乎总是⼿牵⼿在⼀起,成对的。你什么时候看到⼀个 View能够与 不同 View Controller配对?或者反过来?所以,为什么不正规化它们的连接呢? Intermediate 这更准确地描述了你可能已经编写的 MVC代码。但它并没有做太多事情来解决iOS应⽤中 ⽇益增⻓的重量级视图控制器。在典型的 MVC 应⽤⾥,许多逻辑被放在View Controller ⾥。它们中的⼀些确实属于View Controller,但更多的是所谓的“⽤于显示的逻辑”,以 MVVM 属术语来说——就是那些从Model转换数据为 View可以呈现的东⻄的事情,例如 将⼀个NSDate 转换为⼀个格式化过的 NSString。 我们的图解⾥缺少某些东⻄。某些使 我们可以放置所有表示逻辑的东⻄。我们打算将其称为“View Model”——它位于 View/Controller与 Model之间: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 64MVVMModel-View-ViewModel 看起好多了!这个图解准确地描述了什么是 MVVM:⼀个 MVC 的增强版,我们正式连接 了视图和控制器,并将表示逻辑从 Controller 移出放到⼀个新的对象⾥,即 View Model。MVVM 听起来很复杂,但它本质上就是⼀个精⼼优化的 MVC架构,⽽ MVC你早 已熟悉。 好了, 引⾔说完了, 这是⼀个铺垫 . 如果你认为下图右边的⽅法全部放在ViewController⾥ 便于⽇后维护和扩展的话 . 你⼤可固执⼰⻅然后点击浏览器右上⻆的"×" ... 屏幕快照 2015-12-14 下午3.58.00.png 当然, 关于瘦身ViewController有很多⽅⾯ . 然⽽今 天我们讲讲从Controller中分离TableView的表示逻辑 . 为什么引⾔MVVM设计模式, 也是 阐述这个主要思想是相通的 . 就是把"逻辑部分"尽量移到Model层, 你可以认为它是⼀个中 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 65MVVM间层 , 所谓"逻辑部分"可以是各种delegate,⽹络请求,缓存,数据库,coredata等等等等 , ⽽ controller正是⽤来组织串联他们 .使得整个程序⾛通 . 正⽂ 我们很容易想到把 UITableViewDataSource和UITableViewDelegate 的代码提取出 来放到⼀个单独的类. 但我发现还是有东⻄可以抽象出来 . 例如cell的⽣成, cell⾏⾼, 点击 等等 .这⾥我还⽤了block的形式使得函数能够回调 . 如果你对block还不太了解先看这⾥ . 此外, 如果你也重度使⽤.xib⽣成Cell, 那和我封装的类会⾮常契合 . 记住我默认习惯⽤.xib 前的⽂件名来定义cell的Identifier. 如果你想把它⽤于实战, 记得在xib设置cell的Identifier不 要设错. 处理类 XTTableDataDelegate 的 .h #import #import typedef void (^TableViewCellConfigureBlock)(NSIndexPath *indexPath, id item, XTRootCustomCell *cell) ; typedef CGFloat (^CellHeightBlock)(NSIndexPath *indexPath, id item) ; typedef void (^DidSelectCellBlock)(NSIndexPath *indexPath, id item) ; @interface XTTableDataDelegate : NSObject //1 - (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock cellHeightBlock:(CellHeightBlock)aHeightBlock didSelectBlock:(DidSelectCellBlock)didselectBlock ; //2 - (void)handleTableViewDatasourceAndDelegate:(UITableView *)table ; //3 - (id)itemAtIndexPath:(NSIndexPath *)indexPath ; @end 注释: //1. 初始化⽅法: 传数据源, cellIdentifier, 三个block分别对应配置, ⾏⾼, 点击 . //2. 将 UITableViewDataSource和UITableViewDelegate设于XTTableDataDelegate //3. 默认 indexPath.row对应每个dataSource .相应返回item 此外, 为了更彻底, 有必要抽象出"根Cell" .但这样不利于扩展cell . 为了避开model和view的 耦合. 所以使⽤category来做类的扩展 . iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 66MVVM#import @interface UITableViewCell (Extension) + (void)registerTable:(UITableView *)table nibIdentifier:(NSString *)identifier ; - (void)configure:(UITableViewCell *)cell customObj:(id)obj indexPath:(NSIndexPath *)indexPath ; + (CGFloat)getCellHeightWithCustomObj:(id)obj indexPath:(NSIndexPath *)indexPath ; @end 故UITableViewCell+Extension, 通过类的扩展来实现新Cell . 注释: //1 .不解释. //2. 根据数 据源配置并绘制cell ⼦类务必重写该⽅法 //3. 根据数据源计算cell的⾼度 ⼦类可重写该⽅ 法, 若不写为默认值44.0 #pragma mark - Public + (void)registerTable:(UITableView *)table nibIdentifier:(NSString *)identifier { [table registerNib:[self nibWithIdentifier:identifier] forCellReuseIdentifier:identifier] ; } #pragma mark -- #pragma mark - Rewrite these func in SubClass ! - (void)configure:(UITableViewCell *)cell customObj:(id)obj indexPath:(NSIndexPath *)indexPath { // Rewrite this func in SubClass ! } + (CGFloat)getCellHeightWithCustomObj:(id)obj indexPath:(NSIndexPath *)indexPath { // Rewrite this func in SubClass if necessary if (!obj) { return 0.0f ; // if obj is null . } return 44.0f ; // default cell height } iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 67MVVM那么新cell类的实现如下: 实现两个新⽅法 - (void)configure:(UITableViewCell *)cell customObj:(id)obj indexPath:(NSIndexPath *)indexPath { MyObj *myObj = (MyObj *)obj ; MyCell *mycell = (MyCell *)cell ; mycell.lbTitle.text = myObj.name ; mycell.lbHeight.text = [NSString stringWithFormat:@"my Height is : %@", @(myObj.height)] ; cell.backgroundColor = indexPath.row % 2 ? [UIColor greenColor] : [UIColor brownColor] ; } + (CGFloat)getCellHeightWithCustomObj:(id)obj indexPath:(NSIndexPath *)indexPath { return ((MyObj *)obj).height ; } 看下结果, 瘦身后的controller⼲净的不像实⼒派, 只剩下了这⼀个⽅法 .呵呵呵呵 . - (void)setupTableView { self.table.separatorStyle = 0 ; TableViewCellConfigureBlock configureCell = ^(NSIndexPath *indexPath, MyObj *obj, XTRootCustomCell *cell) { [cell configure:cell customObj:obj indexPath:indexPath] ; } ; CellHeightBlock heightBlock = ^CGFloat(NSIndexPath *indexPath, id item) { return [MyCell getCellHeightWithCustomObj:item indexPath:indexPath] ; } ; DidSelectCellBlock selectedBlock = ^(NSIndexPath *indexPath, id item) { NSLog(@"click row : %@",@(indexPath.row)) ; } ; self.tableHander = [[XTTableDataDelegate alloc] initWithItems:self.list cellIdentifier:MyCellIdentifier configureCellBlock:configureCell cellHeightBlock:heightBlock didSelectBlock:selectedBlock] ; [self.tableHander handleTableViewDatasourceAndDelegate:self.table] ; } iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 68MVVM诸多.m⽂件太过于冗⻓,我就不贴到博客了, 博客主要是讲思路, 思路是王道 . 出处@TEASON iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 69MVVMframe与bounds的区别? frame指的是:该view在⽗view坐标系统中的位置和⼤⼩。(参照点是⽗亲的坐标系 统) bounds指的是:该view在本身坐标系统中 的位置和⼤⼩。(参照点是本身坐标系 统) Bounds的⼤⼩改变frame改变吗 会发⽣改变 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 70frame与bounds__block/weak修饰符的区别 __block不管是ARC还是MRC模式下都可以使⽤,可以修饰对象,还可以修饰基本数据类 型 __weak只能在ARC模式下使⽤,也只能修饰对象(NSString),不能修饰基本数据类型 (int) _block对象可以在block中被重新赋值,_weak不可以。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 71__block/weak修饰符的区别awakeFromNib与viewDidLoad区别 awakeFromNib 当 .nib ⽂件被加载的时候,会发送⼀个 awakeFromNib 的消息到 .nib ⽂件中的每个对象, 每个对象都可以定义⾃⼰的 awakeFromNib 函数来响应这个消息,执⾏⼀些必要的操作。也 就是说通过nib⽂件创建view对象是执⾏ awakeFromNib 。 viewDidLoad 当view对象被加载到内存是就会执⾏ viewDidLoad ,所以不管通过nib⽂件还是代码的⽅式 创建对象都会执⾏ viewDidLoad 。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 72awakeFromNib与viewDidLoad区别UIViewController的⽣命周期⽅法调⽤顺序 1. -(void)viewDidLoad; 2. -(void)viewDidUnload; 3. -(void)viewWillAppear:(BOOL)animated; 4. -(void)viewDidAppear:(BOOL)animated; 5. -(void)viewWillDisappear:(BOOL)animated; 6. -(void)viewDidDisappear:(BOOL)animated; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 73UIViewController的⽣命周期⽅法调⽤顺序ViewController的loadView、init等⽅法的调⽤ alloc申请内存时调⽤ loadView加载视图时调⽤ ViewDidLoad视图已经加载后调⽤ ViewWillAppear视图将要出现时调⽤ ViewDidUnload视图已经加载但没有加载出来调⽤ dealloc销毁该视图时调⽤ init视图初始化时调⽤ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 74ViewController的loadView、init等⽅法的调⽤UITableView的执⾏流程是怎么样的 1. numberOfSectionsInTableView: 返回TableView的section数⽬ 2. tableView:titleForHeaderInSection: section1是否有表头标题栏 3. tableView:numberOfRowsInSection: 设置section1中⾏数 1. tableView:heightForRowAtIndexPath: 设置section1中row1⾏的⾼度……row2⾏的⾼ 度……逐⾏设置,直⾄当前section1属性设置完毕 1. tableView:titleForHeaderInSection: section2是否有表头栏,之后同4-5,设置section2 的属性.同理,设置完毕所有的section的相关属性 1. tableView:cellForRowAtIndexPath: 接下来设置的是每个section中每row添加的数据 这样整个TableView就设置完毕了. iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 75UITableView的执⾏流程是怎么样的LayoutSubviews何时会被调⽤ 当要调整subViews时候,需要重写layoutSubviews⽅法。 1. 初始化init⽅法时候不会触发。 2. 滚动UIScrollView时会触发 3. 旋转UIScreen时会触发 4. 当改变view的值时候会触发,前提是frame前后值发⽣了变化 5. 当改变UIview的⼤⼩时候会触发 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 76LayoutSubviews何时会被调⽤应⽤程序按Home键进⼊后台时的⽣命周期 进⼊后台时 -(void)applicationWillResignActive:(UIApplication *)application; -(void)applicationDidEnterBackground:(UIApplication *)application; 进⼊前台时 -(void)applicationDidEnterForeground:(UIApplication *)application; -(void)applicationWillResignActive:(UIApplication *)application; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 77应⽤程序按Home键进⼊后台时的⽣命周期ViewController的didReceiveMemoryWarning是在什么时候 调⽤的?默认的操作是什么 当应⽤程序接收到系统的内容警告时,就有可能调⽤控制器 的 didReceiveMemoryWarning ⽅法 它的默认做法是: 当控制器的view不在窗⼝上显示时,就会直接销毁,并且调⽤viewDidUnload⽅ 法 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 78ViewController的didReceiveMemoryWarning是在什么时候调⽤的?默认的操作是什么tableView的性能优化 最近在微博上看到⼀个很好的开源项⽬VVeboTableViewDemo,是关于如何优化 UITableView的。加上正好最近也在优化项⽬中的类似朋友圈功能这块,思考了很多关于 UITableView的优化技巧,相信这块是难点也是痛点,所以决定详细的整理下我对优化 UITableView的理解。 UITableView作为iOS开发中最重要的控件之⼀,其中的实现原理很是考究。Apple在这块 的优化⽔平直接决定了iOS的体验能甩安卓⼏条街,哈哈,扯淡扯多了。。。好了,废话 不多说,直接进⼊主题。⾸先来谈谈我对UITableView的认识: UITableView的简单认识 UITableView最核⼼的思想就是UITableViewCell的重⽤机制。简单的理解就是: UITableView只会创建⼀屏幕(或⼀屏幕多⼀点)的UITableViewCell,其他都是从中取出 来重⽤的。每当Cell滑出屏幕时,就会放⼊到⼀个集合(或数组)中(这⾥就相当于⼀个 重⽤池),当要显示某⼀位置的Cell时,会先去集合(或数组)中取,如果有,就直接拿 来显示;如果没有,才会创建。这样做的好处可想⽽知,极⼤的减少了内存的开销。 知道UITableViewCell的重⽤原理后,我们来看看UITableView的回调⽅法。UITableView 最主要的两个回调⽅法是tableView:cellForRowAtIndexPath:和 tableView:heightForRowAtIndexPath:。理想上我们是会认为UITableView会先调⽤前者, 再调⽤后者,因为这和我们创建控件的思路是⼀样的,先创建它,再设置它的布局。但实 际上却并⾮如此,我们都知道,UITableView是继承⾃UIScrollView的,需要先确定它的 contentSize及每个Cell的位置,然后才会把重⽤的Cell放置到对应的位置。所以事实上, UITableView的回调顺序是先多次调⽤tableView:heightForRowAtIndexPath:以确定 contentSize及Cell的位置,然后才会调⽤tableView:cellForRowAtIndexPath:,从⽽来显 示在当前屏幕的Cell。 举个例⼦来说:如果现在要显示100个Cell,当前屏幕显示5个。那么刷新(reload) UITableView时,UITableView会先调⽤100次tableView:heightForRowAtIndexPath:⽅ 法,然后调⽤5次tableView:cellForRowAtIndexPath:⽅法;滚动屏幕时,每当Cell滚⼊屏 幕,都会调⽤⼀次tableView:heightForRowAtIndexPath:、 tableView:cellForRowAtIndexPath:⽅法。 看到这⾥,想必⼤伙也都能隐约察觉到, UITableView优化的⾸要任务是要优化上⾯两个回调⽅法。事实也确实如此,下⾯按照我 探讨进阶的过程,来研究如何优化: 优化探索,项⽬拿到⼿时代码是这样: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 79tableview的性能优化- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ContacterTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ContacterTableCell"]; if (!cell) { cell = (ContacterTableCell *)[[[NSBundle mainBundle] loadNibNamed:@"ContacterTableCell" owner:self options:nil] lastObject]; } NSDictionary *dict = self.dataList[indexPath.row]; [cell setContentInfo:dict]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; return cell.frame.size.height; } 看到这段代码,对于刚毕业的我来说,觉得还是蛮巧妙的,但巧归巧,当Cell⾮常复杂的 时候,直接卡出翔了。。。特别是在我的Touch4上,这我能忍?!好吧,依据上⾯ UITableView原理的分析,我们先来分析它为什么卡? 这样写,在Cell赋值内容的时候, 会根据内容设置布局,当然也就可以知道Cell的⾼度,想想如果1000⾏,那就会调⽤ 1000+⻚⾯Cell个数次 tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath ⽅法,⽽我们对Cell的处理操作,都是在这个⽅法⾥的!什么赋值、布局等 等。开销⾃然很⼤,这种⽅案Pass。。。改进代码。 改进代码后: - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *dict = self.dataList[indexPath.row]; return [ContacterTableCell cellHeightOfInfo:dict]; } 思路是把赋值和计算布局分离。这样让tableView:cellForRowAtIndexPath:⽅法只负责赋 值,tableView:heightForRowAtIndexPath:⽅法只负责计算⾼度。注意:两个⽅法尽可能 的各司其职,不要重叠代码!两者都需要尽可能的简单易算。Run⼀下,会发现 UITableView滚动流畅了很多。。。 基于上⾯的实现思路,我们可以在获得数据后,直接 先根据数据源计算出对应的布局,并缓存到数据源中,这样在 tableView:heightForRowAtIndexPath:⽅法中就直接返回⾼度,⽽不需要每次都计算了。 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *dict = self.dataList[indexPath.row]; CGRect rect = [dict[@"frame"] CGRectValue]; return rect.frame.height; } iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 80tableview的性能优化其实上⾯的改进⽅法并不是最佳⽅案,但基本能满⾜简单的界⾯!记得开头我的任务吗? 像朋友圈那样的图⽂混排,这种⽅案还是扛不住的!我们需要进⼊更深层次的探究:⾃定 义Cell的绘制。 我们在Cell上添加系统控件的时候,实质上系统都需要调⽤底层的接⼝进 ⾏绘制,当我们⼤量添加控件时,对资源的开销也会很⼤,所以我们可以索性直接绘制, 提⾼效率。是不是说的很抽象?废话不多说,直接上代码: ⾸先需要给⾃定义的Cell添加 draw⽅法,(当然也可以重写drawRect)然后在⽅法体中实现: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 81tableview的性能优化//异步绘制 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ CGRect rect = [_data[@"frame"] CGRectValue]; UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0); CGContextRef context = UIGraphicsGetCurrentContext(); //整个内容的背景 [[UIColor colorWithRed:250/255.0 green:250/255.0 blue:250/255.0 alpha:1] set]; CGContextFillRect(context, rect); //转发内容的背景 if ([_data valueForKey:@"subData"]) { [[UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1] set]; CGRect subFrame = [_data[@"subData"][@"frame"] CGRectValue]; CGContextFillRect(context, subFrame); [[UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:1] set]; CGContextFillRect(context, CGRectMake(0, subFrame.origin.y, rect.size.width, .5)); } { //名字 float leftX = SIZE_GAP_LEFT+SIZE_AVATAR+SIZE_GAP_BIG; float x = leftX; float y = (SIZE_AVATAR-(SIZE_FONT_NAME+SIZE_FONT_SUBTITLE+6))/2-2+SIZE_GAP_TOP+SIZE_GAP_SMALL-5; [_data[@"name"] drawInContext:context withPosition:CGPointMake(x, y) andFont:FontWithSize(SIZE_FONT_NAME) andTextColor:[UIColor colorWithRed:106/255.0 green:140/255.0 blue:181/255.0 alpha:1] andHeight:rect.size.height]; //时间+设备 y += SIZE_FONT_NAME+5; float fromX = leftX; float size = [UIScreen screenWidth]-leftX; NSString *from = [NSString stringWithFormat:@"%@ %@", _data[@"time"], _data[@"from"]]; [from drawInContext:context withPosition:CGPointMake(fromX, y) andFont:FontWithSize(SIZE_FONT_SUBTITLE) andTextColor:[UIColor colorWithRed:178/255.0 green:178/255.0 blue:178/255.0 alpha:1] andHeight:rect.size.height andWidth:size]; } //将绘制的内容以图⽚的形式返回,并调主线程显示 UIImage *temp = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); dispatch_async(dispatch_get_main_queue(), ^{ if (flag==drawColorFlag) { postBGView.frame = rect; postBGView.image = nil; postBGView.image = temp; } } //内容如果是图⽂混排,就添加View,⽤CoreText绘制 [self drawText]; }} iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 82tableview的性能优化上述代码只贴出来部分功能,但⼤体的思路都是⼀样的,各个信息都是根据之前算好的布 局进⾏绘制的。这⾥是需要异步绘制,但如果在重写drawRect⽅法就不需要⽤GCD异步 线程了,因为drawRect本来就是异步绘制的。对于图⽂混排的绘制,可以移步Google, 研究下CoreText,这块内容太多了,不便展开。 好了,⾄此,我们⼜让UITableView的效 率提⾼了⼀个等级!但我们的步伐还远远不⽌这些,下⾯我们还可以从UIScrollView的⻆ 度出发,再次找到突破⼝。 滑动UITableView时,按需加载对应的内容 直接上代码: //按需加载 - 如果⽬标⾏与当前⾏相差超过指定⾏数,只在⽬标滚动范围的前后指定3⾏加载。 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)]; NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject]; NSInteger skipCount = 8; if (labs(cip.row-ip.row)>skipCount) { NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.width, self.height)]; NSMutableArray *arr = [NSMutableArray arrayWithArray:temp]; if (velocity.y<0) { NSIndexPath *indexPath = [temp lastObject]; if (indexPath.row+33) { [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]]; [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]]; [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]]; } } [needLoadArr addObjectsFromArray:arr]; } } 记得在tableView:cellForRowAtIndexPath:⽅法中加⼊判断: if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) { [cell clear]; return; } 滚动很快时,只加载⽬标范围内的Cell,这样按需加载,极⼤的提⾼流畅度。 写了这么 多,也差不多该来个总结了! UITableView的优化主要从三个⽅⾯⼊⼿: 提前计算并缓存好⾼度(布局),因为heightForRowAtIndexPath:是调⽤最频繁的⽅ 法; 异步绘制,遇到复杂界⾯,遇到性能瓶颈时,可能就是突破⼝; 滑动时按需加载,这个在⼤量图⽚展示,⽹络加载的时候很管⽤!(SDWebImage已 经实现异步加载,配合这条性能杠杠的)。 除了上⾯最主要的三个⽅⾯外,还有很 多⼏乎⼤伙都很熟知的优化点: 正确使⽤reuseIdentifier来重⽤Cells 尽量使所有的view opaque,包括Cell⾃身 尽量少⽤或不⽤透明图层 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 83tableview的性能优化如果Cell内现实的内容来⾃web,使⽤异步加载,缓存请求结果 减少subviews的数量 在heightForRowAtIndexPath:中尽量不使⽤cellForRowAtIndexPath:,如果你需要⽤ 到它,只⽤⼀次然后缓存结果 尽量少⽤addView给Cell动态添加View,可以初始化时就添加,然后通过hide来控制 是否显示 尾巴 肯定很多⼈会⾮常好奇,为什么我都是⼿动⽤代码创建Cell的?现在 主流不都是Xib、Storyboard什么的嘛?我的回答是:要想提⾼效率,还是⼿动写有 ⽤!抛开Xib、Storyboard需要系统⾃动转码,给系统多加了⼀层负担不谈,⾃定义 Cell的绘制更是⽆从下⼿,所以,在我看来,复杂的需要⾼效的界⾯,还是⼿动写代 码吧!!! 最后如果你们的项⽬都是⽤的Xib、Storyboard,并需要优化UITableView的话,sunnyxx ⼤神提出了好的⽅案: http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/ ⼤伙可以⾃⾏研究研究。 知识是需要不断学习的,作为刚上路的我,如果有什么理解不 到位的,欢迎⼤伙留⾔指正,如果你有什么更⽜逼的想法,希望⼀起交流交流。 注明: 本篇的分析源码来源于开源项⽬VVeboTableViewDemo 参 考:https://github.com/johnil/VVeboTableViewDemo 在iOS应⽤中,UITableView应该是使⽤率最⾼的视图之⼀了。iPod、时钟、⽇历、备忘 录、Mail、天⽓、照⽚、电话、短信、 Safari、App Store、iTunes、Game Center⋯⼏乎 所有⾃带的应⽤中都能看到它的身影,可⻅它的重要性。 然⽽在使⽤第三⽅应⽤时,却经常遇到性能上的问题,普遍表现在滚动时⽐较卡,特别是 table cell中包含图⽚的情况时。 实际上只要针对性地优化⼀下,这种问题就不会有了。有兴趣的可以看看 LazyTableImages这个官⽅的例⼦程序,虽然也要从⽹上下载图⽚并显示,但滚动时丝毫 不卡。 下⾯就说说我对UITableView的了解。不过由于我也是初学者,或许会说错或遗漏⼀些, 因此仅供参考。 ⾸先说下UITableView的原理。有兴趣的可以看看 《About Table Views in iOS-Based Applications》。 UITableView是UIScrollView的⼦类,因此它可以⾃动响应滚动事件(⼀ 般为上下滚动)。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 84tableview的性能优化它 内部包含0到多个UITableViewCell对象,每个table cell展示各⾃的内容。当新cell需要 被显示时,就会调⽤tableView:cellForRowAtIndexPath:⽅法来获取或创建⼀个 cell;⽽不 可视时,它⼜会被释放。由此可⻅,同⼀时间其实只需要存在⼀屏幕的cell对象即可,不 需要为每⼀⾏创建⼀个cell。 此 外,UITableView还可以分为多个sections,每个区段都可以有⾃⼰的head、foot和 cells。⽽在定位⼀个cell时,就需要2 个字段了:在哪个section,以及在这个section的第 ⼏⾏。这在iOS SDK中是⽤ NSIndexPath 来表述的,UIKit为其添加 了 indexPathForRow:inSection: 这个创建⽅法。 其他诸如编辑之类的就不提了,因为和本⽂ ⽆关。 介绍完原理,接下来就开始优化吧。 1. 使⽤不透明视图。 不透明的视图可以极⼤地提⾼渲染的速度。因此如⾮必要,可以 将table cell及其⼦视图的opaque属性设为YES(默认值)。 其中的特例包括背景 ⾊,它的alpha值应该为1(例如不要使⽤clearColor);图像的alpha值也应该为1, 或者在画图时设为不透明。 2. 不要重复创建不必要的table cell。 前⾯说了,UITableView只需要⼀屏幕的 UITableViewCell对象即可。因此在cell不可⻅时,可以将其缓存起来,⽽在需要时继 续使⽤它即可。 ⽽UITableView也提供了这种机制,只需要简单地设置⼀个identifier 即可: static NSString *CellIdentifier = @"xxx"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } 值得⼀提的是,cell被重⽤时,它内部绘制的内容并不会被⾃动清除,因此你可能需 要调⽤setNeedsDisplayInRect:或setNeedsDisplay⽅法。 此 外,在添加table cell的时候,如果不需要动画效果,最好不要使 ⽤ insertRowsAtIndexPaths:withRowAnimation: ⽅法,⽽是直接调 ⽤reloadData⽅法。因 为前者会对所有indexPaths调⽤ tableView:cellForRowAtIndexPath: ⽅法,即便该 cell并 不需要显示(不知道是不是bug),这就可能创建⼤量多余的cell。勘误:只是在模拟 器上测试如此,真机调试时没有这种bug。 3. 减少视图的数⽬。 UITableViewCell包含了textLabel、detailTextLabel和imageView 等view,⽽你还可以⾃定义⼀些视图放在它的contentView⾥。然⽽view是很⼤的对 象,创建它会消耗较多资源,并且也影响渲染的性能。 如果你的table cell包含图⽚, 且数⽬较多,使⽤默认的UITableViewCell会⾮常影响性能。奇怪的是,使⽤⾃定义 的view,⽽⾮预定义的view,明显会快些。 当然,最佳的解决办法还是继承 UITableViewCell,并在其drawRect:中⾃⾏绘制: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 85tableview的性能优化 - (void)drawRect:(CGRect)rect { if (image) { [image drawAtPoint:imagePoint]; self.image = nil; } else { [placeHolder drawAtPoint:imagePoint]; } [text drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeTailTruncation]; } 不过这样⼀来,你会发现选中⼀⾏后,这个cell就变蓝了,其中的内容就被挡住了。 最简单的⽅法就是将cell的selectionStyle属性设为 UITableViewCellSelectionStyleNone,这样就不会被⾼亮了。 此 外还可以创建 CALayer,将内容绘制到layer上,然后对cell的contentView.layer调⽤addSublayer: ⽅法。这个例 ⼦中,layer并不会显著影响性能,但如果layer透明,或者有圆⻆、变 形等效果,就会影响到绘制速度了。解决办法可参⻅后⾯的预渲染图像。 4. 不要做多余的绘制⼯作。 在实现drawRect:的时候,它的rect参数就是需要绘制的区 域,这个区域之外的不需要进⾏绘制。 例如上例中,就可以⽤ CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判断是否需要绘 制image和text,然后再调⽤绘制⽅法。 5. 预渲染图像。 你会发现即使做到了上述⼏点,当新的图像出现时,仍然会有短暂的 停顿现象。解决的办法就是在bitmap context⾥先将其画⼀遍,导出成UIImage对 象,然后再绘制到屏幕,详细做法可⻅《利⽤预渲染加速iOS设备的图像显示》。 6. 不要阻塞主线程。 做到前⼏点后,你的table view滚动时应该⾜够流畅了,不过你仍 可能让⽤户感到不爽。常⻅的现象就是在更新数据时,整个界⾯卡住不动,完全不响 应⽤户请求。 出现这种现象的原因就是主线程执⾏了耗时很⻓的函数或⽅法,在其 执⾏完毕前,⽆法绘制屏幕和响应⽤户请求。其中最常⻅的就是⽹络请求了,它通常 都需要花费数秒的时间,⽽你不应该让⽤户等待那么久。 解 决办法就是使⽤多线 程,让⼦线程去执⾏这些函数或⽅法。这⾥⾯还有⼀个学问,当下载线程数超过2 时,会显著影响主线程的性能。因此在使⽤ ASIHTTPRequest时,可以⽤⼀个 NSOperationQueue来维护下载请求,并将其 maxConcurrentOperationCount设为 2。⽽NSURLRequest则可以配合GCD来实现,或者使⽤NSURLConnection的 setDelegateQueue:⽅法。 当然,在不需要响应⽤户请求时,也可以增加下载线程 数,以加快下载速度: - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate) { queue.maxConcurrentOperationCount = 5; } } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { queue.maxConcurrentOperationCount = 5; } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { queue.maxConcurrentOperationCount = 2; } 此外,⾃动载⼊更新数据对⽤户来说也很友好,这减少了⽤户等待下载的时间。例如 每次载⼊50条信息,那就可以在滚动到倒数第10条以内时,加载更多信息: - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if (count - indexPath.row < 10 && !updating) { updating = YES; [self update]; } }// update⽅法获取到结果后,设置updating为NO iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 86tableview的性能优化还有⼀点要注意的就是当图⽚下载完成后,如果cell是可⻅的,还需要更新图像: NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];for (NSIndexPath *visibleIndexPath in indexPaths) { if (indexPath == visibleIndexPath) { MyTableViewCell *cell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; cell.image = image; [cell setNeedsDisplayInRect:imageRect]; break; } }// 也可不遍历,直接与头尾相⽐较,看是否在中间即可。 最后还是前⾯所说过的 insertRowsAtIndexPaths:withRowAnimation: ⽅法,插⼊新⾏需要 在主线程执⾏,⽽⼀次插⼊很多⾏的话(例如50⾏),会⻓时间阻塞主线程。⽽换成 reloadData⽅法的话,瞬间就处理完了。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 87tableview的性能优化tableView的重⽤机制 假如我们有⼀个很⻓的tableview,假设是100⾏,但在我们设计的⾏⾼情况下,屏幕 只能 显示4⾏,所以,当加载view的时候,实际我们需要创建5个cell,总是⽐要显示的cell多⼀ 个,只这4个cell是静态显示,当我们⽤⼿指向上滑动即下⽅的第5个cell向上滑进界⾯的过 程中,我们发现第⼀⾏的cell会滑出界⾯,当滑出后,第⼀⾏这个cell对象会被放到对应重 ⽤标示符重⽤队列中,第5⾏显示在屏幕上。当我继续向上滑动,第⼆⾏的cell对象同样会 放在重⽤队列中,第6个cell将获得重⽤队列中的⼀个cell,这样,这样在后⾯的重⽤中就 就可以正常的⼯作起来了,可以很好的控制内存。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 88tableview的重⽤机制前⾔: 按照时间顺序,事件的⽣命周期是这样的:   事件的产⽣和传递(事件如何从⽗控件 传递到⼦控件并寻找到最合适的view、寻找最合适的view的底层实现、拦截事件的处 理)->找到最合适的view后事件的处理(touches⽅法的重写,也就是事件的响应)    其中重点和难点是:   1. 如何寻找最合适的view   2. 寻找最合适的view的底层实现 (hitTest:withEvent:底层实现)   (⼀)iOS中的事件 iOS中的事件可以分为3⼤类型: 触摸事件 加速计事件 远程控制事件 这⾥我们只讨论iOS中的触摸事件。 1.1. 响应者对象(UIResponder) 学习触摸事件⾸先要了解⼀个⽐较重要的概念-响应者对象 (UIResponder)。 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。以下都是继承⾃UIResponder的,所以都能接收并处理事件。 UIApplication UIViewController UIView 那么为什么继承⾃UIResponder的类就能够接收并处理事件呢? 因为UIResponder中提供了以下4个对象⽅法来处理触摸事件。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 89iOS之事件的传递和响应机制UIResponder内部提供了以下⽅法来处理事件触摸事件 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; 加速计事件 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event; - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event; - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event; 远程控制事件 - (void)remoteControlReceivedWithEvent:(UIEvent *)event; (⼆)事件的处理 下⾯以UIView为例来说明触摸事件的处理。 // UIView是UIResponder的⼦类,可以覆盖下列4个⽅法处理不同的触摸事件 // ⼀根或者多根⼿指开始触摸view,系统会⾃动调⽤view的下⾯⽅法 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event // ⼀根或者多根⼿指在view上移动,系统会⾃动调⽤view的下⾯⽅法(随着⼿指的移动,会持续调⽤该⽅法) - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event // ⼀根或者多根⼿指离开view,系统会⾃动调⽤view的下⾯⽅法- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // 触摸结束前,某个系统事件(例如电话呼⼊)会打断触摸过程,系统会⾃动调⽤view的下⾯⽅法 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event // 提示:touches中存放的都是UITouch对象 需要注意的是:以上四个⽅法是由系统⾃动调⽤的,所以可以通过重写该⽅法来处理⼀些 事件。 如果两根⼿指同时触摸⼀个view,那么view只会调⽤⼀次touchesBegan:withEvent: ⽅法,touches参数中装着2个UITouch对象 如果这两根⼿指⼀前⼀后分开触摸同⼀个view,那么view会分别调⽤2次 touchesBegan:withEvent:⽅法,并且每次调⽤时的touches参数中只包含⼀个 UITouch对象 重 写以上四个⽅法,如果是处理UIView的触摸事件。必须要⾃定义UIView⼦类继承 ⾃UIView。因为苹果不开源,没有把UIView的.m⽂件提 供给我们。我们只能通过⼦ 类继承⽗类,重写⼦类⽅法的⽅式处理UIView的触摸事件(注意:我说的是UIView 触摸事件⽽不是说的 UIViewController的触摸事件)。 如果是处理UIViewController的触摸事件,那么在控制器的.m⽂件中直接重写那四个 ⽅法即可! iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 90iOS之事件的传递和响应机制⾃定义UIView的.h⽂件 #import @interface WSView : UIView @end ⾃定义UIView的.m⽂件 #import "WSView.h" @implementation WSView // 开始触摸时就会调⽤⼀次这个⽅法 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"摸我⼲啥!"); } // ⼿指移动就会调⽤这个⽅法 // 这个⽅法调⽤⾮常频繁 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"哎呀,不要拽⼈家!"); } // ⼿指离开屏幕时就会调⽤⼀次这个⽅法 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"⼿放开还能继续玩耍!"); } @end 控制器的.m⽂件 #import "ViewController.h" #import "WSView.h" @interface ViewController () @end@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 创建⾃定义view WSView *touchView = [[WSView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; // 背景颜⾊ touchView.backgroundColor = [UIColor redColor]; // 添加到⽗控件 [self.view addSubview:touchView]; } @end 注 意:有⼈认为,我要是处理控制器的⾃带的view的事件就不需要⾃定义UIView⼦类继 承于UIView,因为可以在viewController.m ⽂件中重写touchBegan:withEvent:⽅法,但 是,我们此处讨论的是处理UIView的触摸事件,⽽不是处理 UIViewController的触摸事 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 91iOS之事件的传递和响应机制件。你如果是在viewController.m⽂件中重写touchBegan:withEvent:⽅法,相当于处理的 是viewController的触摸事件,因为viewController也是继承⾃UIResponder,所以会给⼈ ⼀种错觉。 所以,还是那句话,想处理UIView的触摸事件,必须⾃定义UIView⼦类继承⾃UIView。 2.1.UIView的拖拽 那么,如何实现UIView的拖拽呢?也就是让UIView随着⼿指的移动⽽移动。   - 重写 touchsMoved:withEvent:   ⽅法此时需要⽤到参数touches,下⾯是UITouch的属性和 ⽅法: NS_CLASS_AVAILABLE_IOS(2_0) @interface UITouch : NSObject @property(nonatomic,readonly) NSTimeInterval timestamp; @property(nonatomic,readonly) UITouchPhase phase; @property(nonatomic,readonly) NSUInteger tapCount; // touch down within a certain point within a certain amount of time // majorRadius and majorRadiusTolerance are in points // The majorRadius will be accurate +/- the majorRadiusTolerance @property(nonatomic,readonly) CGFloat majorRadius NS_AVAILABLE_IOS(8_0); @property(nonatomic,readonly) CGFloat majorRadiusTolerance NS_AVAILABLE_IOS(8_0); @property(nullable,nonatomic,readonly,strong) UIWindow *window; @property(nullable,nonatomic,readonly,strong) UIView *view; @property(nullable,nonatomic,readonly,copy) NSArray *gestureRecognizers NS_AVAILABLE_IOS(3_2); - (CGPoint)locationInView:(nullable UIView *)view; - (CGPoint)previousLocationInView:(nullable UIView *)view; // Force of the touch, where 1.0 represents the force of an average touch @property(nonatomic,readonly) CGFloat force NS_AVAILABLE_IOS(9_0); // Maximum possible force with this input mechanism @property(nonatomic,readonly) CGFloat maximumPossibleForce NS_AVAILABLE_IOS(9_0); 2.1.1.UITouch对象 当⽤户⽤⼀根⼿指触摸屏幕时,会创建⼀个与⼿指相关的UITouch对象 ⼀根⼿指对应⼀个UITouch对象 如果两根⼿指同时触摸⼀个view,那么view只会调⽤⼀次touchesBegan:withEvent: ⽅法,touches参数中装着2个UITouch对象 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 92iOS之事件的传递和响应机制如果这两根⼿指⼀前⼀后分开触摸同⼀个view,那么view会分别调⽤2次 touchesBegan:withEvent:⽅法,并且每次调⽤时的touches参数中只包含⼀个 UITouch对象 2.1.1.1.UITouch的作⽤ 保存着跟⼿指相关的信息,⽐如触摸的位置、时间、阶段 当⼿指移动时,系统会更新同⼀个UITouch对象,使之能够⼀直保存该⼿指在的触摸 位置 当⼿指离开屏幕时,系统会销毁相应的UITouch对象 提 示:iPhone开发中,要避免使 ⽤双击事件! 2.1.1.2.UITouch的属性 触摸产⽣时所处的窗⼝ @property(nonatomic,readonly,retain) UIWindow *window; 触摸产⽣时所处的视图 @property(nonatomic,readonly,retain) UIView *view ; 短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击 @property(nonatomic,readonly) NSUInteger tapCount; 记录了触摸事件产⽣或变化时的时间,单位是秒@property(nonatomic,readonly) NSTimeInterval timestamp; 当前触摸事件所处的状态 @property(nonatomic,readonly) UITouchPhase phase; 2.1.1.3.UITouch的⽅法 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 93iOS之事件的传递和响应机制(CGPoint)locationInView:(UIView *)view; // 返回值表示触摸在view上的位置 // 这⾥返回的位置是针对view的坐标系的(以view的左上⻆为原点(0, 0)) // 调⽤时传⼊的view参数为nil的话,返回的是触摸点在UIWindow的位置 (CGPoint)previousLocationInView:(UIView *)view; // 该⽅法记录了前⼀个触摸点的位置 代码实现: - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ // 想让控件随着⼿指移动⽽移动,监听⼿指移动 // 获取UITouch对象 UITouch *touch = [touches anyObject]; // 获取当前点的位置 CGPoint curP = [touch locationInView:self]; // 获取上⼀个点的位置 CGPoint preP = [touch previousLocationInView:self]; // 获取它们x轴的偏移量,每次都是相对上⼀次 CGFloat offsetX = curP.x - preP.x; // 获取y轴的偏移量 CGFloat offsetY = curP.y - preP.y; // 修改控件的形变或者frame,center,就可以控制控件的位置 // 形变也是相对上⼀次形变(平移) // CGAffineTransformMakeTranslation:会把之前形变给清空,重新开始设置形变参数 // make:相对于最原始的位置形变 // CGAffineTransform t:相对这个t的形变的基础上再去形变 // 如果相对哪个形变再次形变,就传⼊它的形变 self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);} (三)iOS中的事件的产⽣和传递 3.1.事件的产⽣ 发⽣触摸事件后,系统会将该事件加⼊到⼀个由UIApplication管理的事件队列中为什 么是队列⽽不是栈?因为队列的特定是先进先出,先产⽣的事件先处理才符合常理, 所以把事件添加到队列。 UIApplication会从事件队列中取出最前⾯的事件,并将事件分发下去以便处理,通 常,先发送事件给应⽤程序的主窗⼝(keyWindow)。 主窗⼝会在视图层次结构中找到⼀个最合适的视图来处理触摸事件,这也是整个事件 处理过程的第⼀步。找到合适的视图控件后,就会调⽤视图控件的touches⽅法来作 具体的事件处理。 3.2.事件的传递 触摸事件的传递是从⽗控件传递到⼦控件 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 94iOS之事件的传递和响应机制也就是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为透明。 注 意:默认UIImageView不能接受触摸事件,因为不允许交互,即userInteractionEnabled = NO,所以如果希望UIImageView可以交互,需要userInteractionEnabled = YES。 总结⼀下 1. 点击⼀个UIView或产⽣⼀个触摸事件A,这个触摸事件A会被添加到由UIApplication 管理的事件队列中(即,⾸先接收到事件的是UIApplication)。 2. UIApplication会从事件对列中取出最前⾯的事件(此处假设为触摸事件A),把事件A 传递给应⽤程序的主窗⼝(keyWindow)。 3. 窗⼝会在视图层次结构中找到⼀个最合适的视图来处理触摸事件。(⾄此,第⼀步已 完成) 如果想让某个view不能接收事件(或者说,事件传递到某个view那⾥就断了),那么可以 通过刚才提到的三种⽅式。⽐如,设置其userInteractionEnabled = NO;那么传递下来的事 件就会由该view的⽗控件处理。 例如,不想让蓝⾊的view接收事件,那么可以设置蓝⾊ 的view的userInteractionEnabled = NO;那么点击⻩⾊的view或者蓝⾊的view所产⽣的事 件,橙⾊的view就会成为最合适的view。事件都会由橙⾊的veiw处理。 所以,不管视图 能不能处理事件,只要点击了视图就都会产⽣事件,关键看该事件是由谁来处理!也就是 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 95iOS之事件的传递和响应机制说,如果视图不能处理事件,点击视图,还是会产⽣⼀个触摸事件,只是该事件不会由被 点击的视图处理⽽已! 注意:如果设置⽗控件的透明度或者hidden,会直接影响到⼦控 件的透明度和hidden。如果⽗控件的透明度为0或者hidden = YES,那么⼦控件也是不可 ⻅的! 3.3.(重难点)如何寻找最合适的view 应⽤如何找到最合适的控件来处理事件? 1. ⾸先判断主窗⼝(keyWindow)⾃⼰是否能接受触摸事件 2. 触摸点是否在⾃⼰身上 3. 从后往前遍历⼦控件,重复前⾯的两个步骤(⾸先查找数组中最后⼀个元素) 4. 如果没有符合条件的⼦控件,那么就认为⾃⼰最合适处理 详述: 1. 主窗⼝接收到应⽤程序传递过来的事件后,⾸先判断⾃⼰能否接⼿触摸事件。如果 能,那么在判断触摸点在不在窗⼝⾃⼰身上    2. 如果触摸点也在窗⼝身上,那么窗⼝会从后往前遍历⾃⼰的⼦控件(遍历⾃⼰的⼦控 件只是为了寻找出来最合适的view)   3. 遍历到每⼀个⼦控件后,⼜会重复上⾯的两个步骤(传递事件给⼦控件,1.判断⼦控 件能否接受事件,2.点在不在⼦控件上)  4. 如此循环遍历⼦控件,直到找到最合适的view,如果没有更合适的⼦控件,那么⾃⼰ 就成为最合适的view。找到最合适的view后,就会调⽤该view的touches⽅法处理具 体的事件。所以,只有找到最合适的view,把事件传递给最合适的view后,才会调⽤ touches⽅法进⾏接下来的事件处理。找不到最合适的view,就不会调⽤touches⽅法 进⾏事件处理。 注意:之所以会采取从后往前遍历⼦控件的⽅式寻找最合适的view只是为了做⼀些循环优 化。因为相⽐较之下,后添加的view在上⾯,降低循环次数。 3.3.1.寻找最合适的view底层剖析 两个重要的⽅法: hitTest:withEvent:⽅法 pointInside⽅法 3.3.1.1.hitTest:withEvent:⽅法 什么时候调⽤? iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 96iOS之事件的传递和响应机制只要事件⼀传递给⼀个控件,这个控件就会调⽤他⾃⼰的 hitTest:withEvent: ⽅法 作⽤ 寻找并返回最合适的view(能够响应事件的那个最合适的view) 注 意:不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传 递给这个控件,随后再调⽤ hitTest:withEvent: ⽅法 拦截事件的处理 正因为 hitTest:withEvent: ⽅法可以返回最合适的view,所以可以通过重写 hitTest: withEvent: ⽅法,返回指定的view作为最合适的view。 不管点击哪⾥,最合适的view都是 hitTest:withEvent: ⽅法中返回的那个view。 通过重写 hitTest:withEvent: ,就可以拦截事件的传递过程,想让谁处理事件谁就处 理事件。 事件传递给谁,就会调⽤谁的 hitTest:withEvent: ⽅法。 注 意:如果 hitTest:withEvent: ⽅法中返回nil,那么调⽤该⽅法的控件本身和其⼦控件都 不是最合适的view,也就是在⾃⼰身上没有找到更合适的view。那么最合适的view就是该 控件的⽗控件。 所以事件的传递顺序是这样的:   产⽣触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[⼦控件 hitTest:withEvent:]->返回最合适的view    事件传递给窗⼝或控件的后,就调⽤hitTest:withEvent:⽅法寻找更合适的view。所以是,先传递事件,再根据事件在⾃⼰身上找更合适的view。不管⼦控件是不是最合适的view,系统默认都要先把事件传递给⼦控件,经过⼦控件调⽤⾃⼰的hitTest:withEvent:⽅法验证后才知道有没有更合适的view。即便⽗控件是最合适的view了,⼦控件的hitTest:withEvent:⽅法还是会调⽤,不然怎么知道有没有更合适的!即,如果确定最终⽗控件是最合适的view,那么该⽗控件的⼦控件的hitTest:withEvent:⽅法也是会被调⽤的。 技巧:想让谁成为最合适的view就重写谁⾃⼰的⽗控件的hitTest:withEvent:⽅法返回指定 的⼦控件,或者重写⾃⼰的hitTest:withEvent:⽅法 return self。但是,建议在⽗控件的 hitTest:withEvent:中返回⼦控件作为最合适的view! 原因在于在⾃⼰的hitTest:withEvent:⽅法中返回⾃⼰有时候会出现问题,因为会存在这么 ⼀种情况,当遍历⼦控件时,如果触摸点不在⼦控件A⾃⼰身上⽽是在⼦控件B身上,还 要要求返回⼦控件A作为最合适的view,采⽤返回⾃⼰的⽅法可能会导致还没有来得及遍 历A⾃⼰,就有可能已经遍历了点真正所在的view,也就是B。这就导致了返回的不是⾃ ⼰⽽是点真正所在的view。所以还是建议在⽗控件的hitTest:withEvent:中返回⼦控件作为 最合适的view! iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 97iOS之事件的传递和响应机制例如:whiteView有redView和greenView两个⼦控件。redView先添加,greenView后添 加。如果要求⽆论点击那⾥都要让redView作为最合适的view(把事件交给redView来处 理)那么只能在whiteView的hitTest:withEvent:⽅法中return self.subViews[0];这种情况下 在redView的hitTest:withEvent:⽅法中return self;是不好使的! // 这⾥redView是whiteView的第0个⼦控件 #import "redView.h" @implementation redView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ return self; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"red-touch"); }@end // 或者 #import "whiteView.h" @implementation whiteView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ return self.subviews[0]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"white-touch"); } @end 特殊情况:谁都不能处理事件,窗⼝也不能处理。 重写window的hitTest:withEvent:⽅法return nil 只能有窗⼝处理事件。 控制器的view的hitTest:withEvent:⽅法return nil或者window的hitTest: withEvent:⽅法return self return nil的含义: hitTest:withEvent:中return nil的意思是调⽤当前hitTest: withEvent:⽅法的view不是合适的view,⼦控件也不是合适的view。如果同级的兄弟控 件也没有合适的view,那么最合适的view就是⽗控件。 寻找最合适的view底层剖析之hitTest:withEvent:⽅法底层做法/ hitTest:withEvent:⽅ 法底层实现/ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 98iOS之事件的传递和响应机制#import "WSWindow.h" @implementation WSWindow // 什么时候调⽤:只要事件⼀传递给⼀个控件,那么这个控件就会调⽤⾃⼰的这个⽅法 // 作⽤:寻找并返回最合适的view // UIApplication -> [UIWindow hitTest:withEvent:]寻找最合适的view告诉系统 // point:当前⼿指触摸的点 // point:是⽅法调⽤者坐标系上的点 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ // 1.判断下窗⼝能否接收事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; // 2.判断下点在不在窗⼝上 // 不在窗⼝上 if ([self pointInside:point withEvent:event] == NO) return nil; // 3.从后往前遍历⼦控件数组 int count = (int)self.subviews.count; for (int i = count - 1; i >= 0; i--) { // 获取⼦控件 UIView *childView = self.subviews[i]; // 坐标系的转换,把窗⼝上的点转换为⼦控件上的点 // 把⾃⼰控件上的点转换成⼦控件上的点 CGPoint childP = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childP withEvent:event]; if (fitView) { // 如果能找到最合适的view return fitView; } } // 4.没有找到更合适的view,也就是没有⽐⾃⼰更合适的view return self; } // 作⽤:判断下传⼊过来的点在不在⽅法调⽤者的坐标系上 // point:是⽅法调⽤者坐标系上的点 //- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event //{ // return NO; //} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"%s",__func__); } @end hit:withEvent:⽅法底层会调⽤pointInside:withEvent:⽅法判断点在不在⽅法调⽤者的 坐标系上。 3.3.1.2.pointInside:withEvent:⽅法 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 99iOS之事件的传递和响应机制pointInside:withEvent:⽅法判断点在不在当前view上(⽅法调⽤者的坐标系上)如果返回 YES,代表点在⽅法调⽤者的坐标系上;返回NO代表点不在⽅法调⽤者的坐标系上,那么 ⽅法调⽤者也就不能处理事件。 (四)事件的响应 4.1.触摸事件处理的整体过程 1>⽤户点击屏幕后产⽣的⼀个触摸事件,经过⼀系列的传递过程后,会找到最合适的视图 控件来处理这个事件2>找到最合适的视图控件后,就会调⽤控件的touches⽅法来作具体 的事件处理touchesBegan…touchesMoved…touchedEnded…3>这些touches⽅法的默认 做法是将事件顺着响应者链条向上传递(也就是touch⽅法默认不处理事件,只传递事 件),将事件交给上⼀个响应者进⾏处理 4.2.响应者链条示意图 响应者链条:在iOS程序中⽆论是最后⾯的UIWindow还是最前⾯的某个按钮,它们的摆放 是有前后关系的,⼀个控件可以放到另⼀个控件上⾯或下⾯,那么⽤户点击某个控件时是 触发上⾯的控件还是下⾯的控件呢,这种先后关系构成⼀个链条就叫“响应者链”。也可以 说,响应者链是由多个响应者对象连接起来的链条。在iOS中响应者链的关系 可以⽤下图 表示: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 100iOS之事件的传递和响应机制响应者对象:能处理事件的对象,也就是继承⾃UIResponder的对象 作⽤:能很清楚的看 ⻅每个响应者之间的联系,并且可以让⼀个事件多个对象处理。 如何判断上⼀个响应者 1. 如果当前这个view是控制器的view,那么控制器就是上⼀个响应者 2. 如果当前这个view不是控制器的view,那么⽗控件就是上⼀个响应者 响应者链的事件传递过程: 1. 如果当前view是控制器的view,那么控制器就是上⼀个响应者,事件就传递给控制 器;如果当前view不是控制器的view,那么⽗视图就是当前view的上⼀个响应者,事 件就传递给它的⽗视图 2. 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消 息传递给window对象进⾏处理 3. 如果window对象也不处理,则其将事件或消息传递给UIApplication对象 4. 如果UIApplication也不能处理该事件或消息,则将其丢弃 事件处理的整个流程总结: 1. 触摸屏幕产⽣触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中 (即,⾸先接收到事件的是UIApplication)。  2. UIApplication会从事件队列中取出最前⾯的事件,把事件传递给应⽤程序的主窗⼝ (keyWindow)。   3. 主窗⼝会在视图层次结构中找到⼀个最合适的视图来处理触摸事件。(⾄此,第⼀步 已完成)   4. 最合适的view会调⽤⾃⼰的touches⽅法处理事件  5.touches默认做法是把事件顺 着响应者链条向上抛。 touches的默认做法: #import "WSView.h" @implementation WSView //只要点击控件,就会调⽤touchBegin,如果没有重写这个⽅法,⾃⼰处理不了触摸事件 // 上⼀个响应者可能是⽗控件 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ // 默认会把事件传递给上⼀个响应者,上⼀个响应者是⽗控件,交给⽗控件处理 [super touchesBegan:touches withEvent:event]; // 注意不是调⽤⽗控件的touches⽅法,⽽是调⽤⽗类的touches⽅法 // super是⽗类 superview是⽗控件 } @end iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 101iOS之事件的传递和响应机制事件的传递与响应: 1、当⼀个事件发⽣后,事件会从⽗控件传给⼦控件,也就是说由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的传递,也就是寻找最合适的view的过 程。 2、接下来是事件的响应。⾸先看initial view能否处理这个事件,如果不能则会将事件传递 给其上级视图(inital view的superView);如果上级视图仍然⽆法处理则会继续往上传 递;⼀直传递到视图控制器view controller,⾸先判断视图控制器的根视图view是否能处 理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上 传 递;(对于第⼆个图视图控制器本身还在另⼀个视图控制器中,则继续交给⽗视图控 制器的根视图,如果根视图不能处理则交给⽗视图控制器处理);⼀直到 window,如果 window还是不能处理此事件则继续交给application处理,如果最后application还是不能处 理此事件则将其丢弃 3、在事件的响应中,如果某个控件实现了touches...⽅法,则这个事件将由该控件来接 受,如果调⽤了[supertouches….];就会将事件顺着响应者链条往上传递,传递给上⼀个响 应者;接着就会调⽤上⼀个响应者的touches….⽅法 如何做到⼀个事件多个对象处理: 因为系统默认做法是把事件上抛给⽗控件,所以可以 通过重写⾃⼰的touches⽅法和⽗控件的touches⽅法来达到⼀个事件多个对象处理的⽬ 的。 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ // 1.⾃⼰先处理事件... NSLog(@"do somthing..."); // 2.再调⽤系统的默认做法,再把事件交给上⼀个响应者处理 [super touchesBegan:touches withEvent:event]; } 事件的传递和响应的区别:事件的传递是从上到下(⽗控件到⼦控件),事件的响应是从 下到上(顺着响应者链条向上传递:⼦控件到⽗控件。 来⾃简书作者: VV⽊公⼦ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 102iOS之事件的传递和响应机制⽹络部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 103⽹络部分http的post与get区别与联系,实践中如何选择它们? 1. get是从服务器上获取数据,post是向服务器传送数据。 2. 在客户端,Get⽅式在通过URL提交数据,数据在URL中可以看到;POST⽅式,数 据放置在HTML HEADER内提交。 3. 对于get⽅式,服务器端⽤Request.QueryString获取变量的值,对于post⽅式,服务 器端⽤Request.Form获取提交的数据。 4. GET⽅式提交的数据最多只能有1024字节,⽽POST则没有此限制。 5. 安全性问题。正如在(1)中提到,使⽤ Get 的时候,参数会显示在地址栏上,⽽ Post 不会。所以,如果这些数据是中⽂数据⽽且是⾮敏感数据,那么使⽤ get;如果 ⽤户输⼊的数据不是中⽂字符⽽且包含敏感数据,那么还是使⽤ post为好。 Http定义了与服务器交互的不同⽅法,最基本的⽅法有4种,分别是GET,POST,PUT, DELETE。URL全称是资源描述符,我们可以这样认为:⼀个URL地址,它⽤于描述⼀个 ⽹络上的资源,⽽HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查, 改,增,删4个操作。GET⼀般⽤于获取/查询资源信息,⽽POST⼀般⽤于更新资源信 息。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 104http的post与get区别与联系OAuth授权 OAuth 协议为⽤户资源的授权提供了⼀个安全的、开放⽽⼜简易的标准 OAuth 的授权不会使第三⽅触及到⽤户的帐号信息 OAuth 允许⽤户提供⼀个令牌,⽽不是⽤户名和密码来访问他们存放在特定服务提供 者的数据 每⼀个令牌授权⼀个 特定的⽹站 在 特定的时段内 访问 特定的资源 OAuth解决第三⽅应⽤在不知道⽤户密码的情况下可以获得⽤户的特定数据 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 105OAuth授权这样 我们获取了access Token 便可以在不知道⽤户账号密码的情况下访问⽤户的数据 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 106OAuth授权多线程部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 107多线程部分线程与进程的区别和联系 ⼀个进程可以由⼀个或者多个线程组成 进程和程序并不是⼀⼀对应的,⼀个程序执⾏在不同的数据集上就成为不同的进程, 可以⽤进程控制块来唯⼀地标识每个进程。⽽这⼀点正是程序⽆法做到的,由于程序 没有和数据产⽣直接的联系,既使是执⾏不同的数据的程序,他们的指令的集合依然 是⼀样的,所以⽆法唯⼀地标识出这些运⾏于不同数据集上的程序。⼀般来说,⼀个 进程肯定有⼀个与之对应的程序,⽽且只有⼀个。⽽⼀个程序有可能没有与之对应的 进程(因为它没有执⾏), 也有可能有多个进程与之对应(运⾏在⼏个不同的数据集上)。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 108线程与进程的区别和联系谈谈你对多线程开发的理解?ios中有⼏种实现多线程的⽅法? 好处: 1. 使⽤线程可以把占据时间⻓的程序中的任务放到后台去处理 2. ⽤户界⾯可以更加吸引⼈,这样⽐如⽤户点击了⼀个按钮去触发某些事件的处理,可 以弹出⼀个进度条来显示处理的进度 3. 程序的运⾏速度可能加快 4. 在⼀些等待的任务实现上如⽤户输⼊、⽂件读写和⽹络收发数据等,线程就⽐较有⽤ 了。 缺点: 1. 如果有⼤量的线程,会影响性能,因为操作系统需要在它们之间切换。 2. 更多的线程需要更多的内存空间。 3. 线程的中⽌需要考虑其对程序运⾏的影响。 4. 通常块模型数据是在多个线程间共享的,需要防⽌线程死锁情况的发⽣。 实现多线程的⽅法: NSObject类⽅法 NSThread NSOperation GCD iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 109对多线程开发的理解多线程安全 1. 只在主线程刷新访问UI 2. 如果要防⽌资源抢夺,得⽤synchronized进⾏加锁保护 3. 如果异步操作要保证线程安全等问题, 尽量使⽤GCD(有些函数默认就是安全的) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 110多线程安全GCD内部怎么实现的 1. iOS和OS X的核⼼是XNU内核,GCD是基于XNU内核实现的 2. GCD的API全部在libdispatch库中 3. GCD的底层实现主要有Dispatch Queue和Dispatch Source Dispatch Queue :管理block(操作) Dispatch Source :处理事件(MACH端⼝发送,MACH端⼝接收,检测与进程相关 事件等10种事件) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 111gcd内部怎么实现的检查内存管理问题的⽅式有哪些? 1. 点击Xcode顶部菜单中的Product-Analyze。这种⽅法主要可以查看内存泄露,变量未 初始化,变量定义后没有被使⽤到 1. 使⽤Instrument⼯具检查。点击Xcode顶部菜单中的ProductàProfile,弹出⼀个界 ⾯,选择左侧的Memory后,再选右侧的Leaks。 1. ⼈⼯检查 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 112检查内存管理问题的⽅式有哪些?怎么解决缓存池满的问题(cell) ios中不存在缓存池满的情况,因为通常我们ios中开发,对象都是在需要的时候才会创 建,有种常⽤的说话叫做懒加载,还有在UITableView中⼀般只会创建刚开始出现在屏幕 中的cell,之后都是从缓存池⾥取,不会在创建新对象。缓存池⾥最多也就⼀两个对象, 缓存池满的这种情况⼀般在开发java中⽐较常⻅,java中⼀般把最近最少使⽤的对象先释 放。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 113怎么解决缓存池满的问题(cell)补充实⽤部分 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 114补充实⽤部分IDE的介绍 什么是 IDE ? IDE是 Integrated Development Environment 的简称,叫做集成开发环境. 集成开发环境作何解释? 环境: 就是1个软件. 开发环境: ⽤于开发程序的1个软件,就是说这个软件是⽤来开发程序的。 集成开发环境: 集成的意思是多个功能集合在⼀起的意思,所以就是集多种功能于 1身的⽤来开发程序的软件。 不同的开发平台具有不同的IDE的⼯具 ⽐如开发Java程序的IDE⼯具是eclipse 开发.Net程序的IDE⼯具是Visual Studio 开发PHP程序的IDE⼯具是Zend Studio. ⽽开发我们iOS程序的IDE⼯具是Xcode iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 115ide的介绍Coredata ⼀. CoreData 是什么? Core Data 是 iOS SDK ⾥的⼀个很强⼤的框架,允许程序员以⾯向对象的⽅式储存和 管理数据。使⽤ Core Data 框架,程序员可以很轻松有效地通过⾯向对象的接⼝管理 数据 Core Data 是⼀个模型层的技术。帮助建⽴代表程序状态的模型层,Core Data 也是⼀ 种 持久化技术,能将模型对象的状态持久化到磁盘,但它最重要的特点是: Core Data 不仅是⼀个加载、保存数据的框架,它还能和内存中的数据很好的共事 在数据操作过程中, ⽆需编写任何SQL语句 Core Data 使⽤包括实体和实体间关系,以及查找符合某些条件实体的请求等内容 开发者可以在纯对象层上查找与管理这些数据,⽽不必担⼼存储和查找的实现细节 Core Data 框架最早出现在 Mac OS X 10.4 Tiger 与 iOS 3.0 系统,经过成千上万的应 ⽤程序以及数以百万⽤户的反复的验证,Core Data 确实已经是⼀套⾮常成熟的框架 CoreData利⽤了Objective-C语⾔和运⾏时,巧妙地集成了CoreFoundation框架。是 ⼀ 个易于使⽤的框架,不仅可以优雅地管理对象图,⽽且在内存管理⽅⾯表现异常优异 ⼆. 怎么学习CoreData 第⼀眼看到 Core Data 令⼈⽣畏的复杂架构关系,很多⼈都会有⽆从下⼿的感觉. 可是, ⼀旦理解了架构图中各个部件的组成及相互之间的关系,就能体会到 Core Data API 的简洁和直观了 Core Data stack(堆栈):如果能够理解 Core Data stack 中的各个成员所扮演的⻆⾊, 那么再使⽤Core Data 就不会感觉到困难了 误区:Core Data 不是⼀个数据库,不要⽤数据库的眼光去看待 Core Data Core Data 不是应⽤程序的数据库,也不是将数据持久化保存到数据库的 API。Core Data 是⼀个⽤于管理对象图的框架。Core Data 可以把对象图写⼊磁盘从⽽持久化 保存,但是这不是框架的主要⽬标. iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 116coredata三. Core Data stack Core Data stack 是 Core Data 的核⼼,由⼀组 Core Data 核⼼对象组成 NSManagedObjectContext 对象管理上下⽂: 负责管理模型的对象的集合 NSManagedObjectModel 被管理的对象模型: 负责管理对象模型 NSPersistentStoreCoordinator 存储调度器: 负责将数据保存到磁盘的 三者之间关系示意图: 分为两部分: 对象图管理 数据持久化 在这两部分的中间,即堆栈中间,是持久化存储协调器(Persistent Store Coordinator, PSC)。通过它将对象图管理部分和持久化部分绑在⼀起。当这两部分中 的⼀部分需要和另⼀部分交互,将通过 PSC 来调节 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 117coredata常⻅的使⽤解决⽅案: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 118coredata四. 创建CoreDataStack 根据 CoreDataStack 示意图,将关系以代码的形式组织起来 ! // 实例化数据模型 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelNamewithExtension:@"momd"]; NSManagedObjectModel *model = [[NSManagedObjectModel alloc]initWithContentsOfURL:modelURL]; // 实例化持久化储存 NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; NSURL *dbURL = [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject]; dbURL = [dbURL URLByAppendingPathComponent:dbName];[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:dbURL options:nil error:NULL]; // 实例化上下⽂ _managedObjectContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType]; [_managedObjectContext setPersistentStoreCoordinator:psc]; [ ⼀些提示 ] use scalar properties for primitive data type iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 119coredata在 iOS5 和 OS X10.7 之前,scalar 不能⾃动⽣成,程序员必须⾃⼰添加 setter 和 getter 的 实现 @dynamic 在 Objective-C 中,如果将某个属性实现为@dynamic,意味着告诉编译器不会在编译时确定 这个属性的⾏为实现,因此不需要在编译期间对这个属性的 getter、setter 做检查. 五. CoreData 常⻅操作 5.1 新增记录: 使⽤ NSEntityDescription 来创建对象,赋值后使⽤相应的 context 保存即可 5.2 删除记录: 使⽤ context 的 deleteObject:删除被管理的模型对象后保存即可 5.3 修改记录: 直接修改模型对象保存即可 5.4 查询记录 对使⽤ CoreData 进⾏存储的数据进⾏⼀定条件的查询后取出来使⽤ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 120coredata5.4.1 谓词(is)---NSPredicate 作⽤:判断条件表达式的求值返回真或假的过程 使⽤步骤: 定义 NSPredicate 对象并指定条件 调⽤谓词的 evaluateWithObject ⽅法判断指定条件是否满⾜示例: NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self CONTAINS '1'"]; NSString *text = @"1234"; NSLog(@"%d", [predicate evaluateWithObject:text]); 案例: 1. 创建 Person 的对象数组 2. 查询判断姓名和年龄的过滤⽅法 传统⽅法 NSMutableArray *result = [NSMutableArray arrayWithCapacity:personList.count]; for (NSInteger i = 0; i < personList.count; i++) { Person *person = personList[i]; // ⽤户年龄⼩于5同时⽤户姓名中包含"1"字符串 if (person.age < 5 && NSNotFound != [person.name rangeOfString:@"1"].location) { [result addObject:person]; } } return result; 谓词⽅法 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name CONTAINS '1' && %K BETWEEN {%d, %d}",@"age", 5, 15]; NSArray *result = [personList filteredArrayUsingPredicate:predicate]; 谓词的条件指令 1. > < == >= <= != 例如: @"number >= 99" 2. 范围运算符 IN BETWEEN 例如: @"number BETWEEN {1,5}" @"address IN {'shanghai','nanjing'}" iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 121coredata3. 字符串本身 :SELF 例如: @"SELF == 'APPLE'" 4. 字符串相关: BEGINSWITH ENDSWITH CONTAINS 例如: @"name CONTAIN[cd] 'ang'" //包含某个字符串 @"name BEGINSWITH[c] 'sh'" //以某个字符串开头 @"name ENDSWITH[d] 'ang'" //以某个字符串结尾 5. 通配符: LIKE 例如: @"name LIKE[cd] '*er*'" //* 代表通配符,Like 代表接受 [cd]. @"name LIKE[cd] '???er*'" 注: 星号"*" : 代表0或多个字符 问号"?" : 代表⼀个字符 6. 正则表达式:MATCHES 例如: NSString *regex = @"^A.+e$"; //以A开头, e结尾 @"name MATCHES %@",regex 注:[c]不区分⼤⼩写,[d]不区分发⾳符号即没有重⾳符号,[cd]既不区分⼤⼩写,也不区分发⾳符号. 7. 合计操作 ANY SOME: 指定下列表达式中的任意元素 例如 ANY children.age < 18 ALL: 指定下列表达式中的所有元素 例如 ALL children.age < 18 NONE: 指定下列表达 式中没有的元素 例如 NONE children.age < 18 在逻辑上等于NOT(ANY ...) IN:等于 SQL的 IN 操作,左边的表达必须出现在与右边指定的集合中 例如: name IN { 'Ben','Melissa', 'Nick' } 提示 : 1. 谓词中的匹配指令关键字通常使⽤⼤写字⺟ 2. 谓词中可以使⽤格式字符串 3. 如果通过对象的 key path 指定匹配条件,需要使⽤ %K iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 122coredataiOS6、7、8、9新特性汇总和适配说明 iOS6新特性 ⼀、关于内存警告 ios6中废除了viewDidUnload,viewWillUnload这两个系统回调,收到内存警告时在 didReceiveMemoryWarning中进⾏相关的处理。 - (void)viewDidUnload { [super viewDidUnload]; // 处理 ios6 以下的系统内存警告系统回调消息 } // 这⾥处理ios6 的内存警告 - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; float sysVer = [[[UIDevice currentDevice] systemVersion] floatValue]; //ios6 的特殊处理 if (sysVer >= 6.0f) { // 保证 invisible, 因为即使在当前界⾯也会收到系统回调 if (self.view.window == nil) { //....... // 做相关的释放操作 self.view = nil; // 确保下次会重新加载 } } } ⼆、关于屏幕旋转 同样ios6 废除了shouldAutorotateToInterfaceOrientation这个旋转屏幕的设置接⼝。 必须在两个新接⼝中设置旋转属性:shouldAutorotate、supportedInterfaceOrientations。 收到旋转事件后的处理,同样在willRotateToInterfaceOrientation和 didRotateFromInterfaceOrientation中进⾏。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 123iOS6、7、8、9新特性汇总和适配说明三、UISwitch ios6下,新增了以下⼏个属性,可以设置开关的颜⾊以及背景图。 @property (nonatomic, retain) UIColor *tintColor; @property (nonatomic, retain) UIColor *thumbTintColor; @property (nonatomic, retain) UIImage *onImage; @property (nonatomic, retain) UIImage *offImage; 四、UINavigationBar ios6新增了,设置阴影图⽚的属性。 @property (nonatomic, retain) UIImage *shadowImage; 五、UIImage 可以在ios6下设置图⽚的scale⽐例尺⼨了。 + (UIImage *)imageWithData:(NSData *)data scale:(CGFloat)scale; - (id)initWithData:(NSData *)data scale:(CGFloat)scale; 六、UIRefreshControl 之前苹果官⽅是没有现成的下拉刷新的控件,都是⾃⼰实现或者使⽤⽐较成熟的开源库。 ios6苹果加⼊了UIRefreshControl,配合UITableView直接实现下拉刷新。 七、UICollectionView 全新的集合控件,应⽤场景有类似照⽚墙,瀑布流等。 iOS7新特性 ⼀、已禁⽤-[UIDevice uniqueIdentifier] iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 124iOS6、7、8、9新特性汇总和适配说明苹果总是把⽤户的隐私看的很重要。-[UIDevice uniqueIdentifier]在iOS5实际在iOS5的时 候已经被遗弃了,但是iOS7中已经完全的禁⽤了它。Xcode5甚⾄不会允许你编译包含了 指引到-[UIDevice uniqueIdentifier]的app。 此外,iOS7之前的使⽤了-[UIDevice uniqueIdentifier] 的app如果在iOS7上运⾏,它不会 返回设备的UUID,⽽是会返回⼀串字符串,以FFFFFFFF开头,跟着-[UIDevice identifierForVendor]的⼗六进制值。 ⼆、UIPasteboard由共享变为沙盒化了 UIPasteboard过去是⽤来做app之间的数据分享的。UIPasteboard本⽆问题,但是开发者 开始使⽤它来存储标识符,和其他的相关app分享这些标识符的时候问题就出现了。有⼀ 个使⽤这种把戏的就是OpenUDID。 在iOS7中,使⽤ +[UIPasteboard pasteboardWithName:create:]和 +[UIPasteboard pasteboardWithUniqueName]创建剪贴板,⽽且只对相同的app group可⻅,这样就让 OpenUDID不那么有⽤了。 三、MAC地址不能再⽤来设别设备 还有⼀个⽣成iOS设备唯⼀标示符的⽅法是使⽤iOS设备的Media Access Control(MAC)地址。⼀个MAC地址是⼀个唯⼀的号码,它是物理⽹络层级⽅⾯分配给 ⽹络适配器的。这个地址苹果还有其他的名字,⽐如说是硬件地址(Hardware Address) 或是Wifi地址,都是指同样的东⻄。 有很多⼯程和框架都使⽤这个⽅法来⽣成唯⼀的设备ID。⽐如说ODIN。然⽽,苹果并不 希望有⼈通过MAC地址来分辨⽤户,所以如果你在iOS7系统上查询MAC地址,它现在只 会返回02:00:00:00:00:00。 现在苹果明确的表明你应该使⽤-[UIDevice identifierForVendor]或是- [ASIdentifierManager advertisingIdentifier]来作为你框架和应⽤的唯⼀标示符。坦⽩的来 说,应对这些变化也不是那么的难,⻅以下代码⽚段: NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString]; NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; 每种⽅法都适配⼀种特别的⽤法: identifierForVendor对供应商来说是唯⼀的⼀个值,也就是说,由同⼀个公司发⾏的的app 在相同的设备上运⾏的时候都会有这个相同的标识符。然⽽,如果⽤户删除了这个供应商 的app然后再重新安装的话,这个标识符就会不⼀致。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 125iOS6、7、8、9新特性汇总和适配说明advertisingIdentifier会返回给在这个设备上所有软件供应商相同的 ⼀个值,所以只能在⼴ 告的时候使⽤。这个值会因为很多情况⽽有所变化,⽐如说⽤户初始化设备的时候便会改 变。 四、iOS现在要求app如需使⽤⻨克⻛,需要征得⽤户同意 以前如果app需要使⽤⽤户的位置,通讯录,⽇历,提醒以及照⽚,接受推送消息,使⽤ ⽤户的社交⽹络的时候需要征得⽤户的同意。现在在iOS7当中,使⽤⻨克⻛也需要取得⽤ 户同意了。如果⽤户不允许app使⽤⻨克⻛的话,那么需要使⽤⻨克⻛的app就不能接收 不到任何声⾳。 以下的代码是⽤来查询⽤户是否允许app使⽤⻨克⻛: //第⼀次调⽤这个⽅法的时候,系统会提示⽤户让他同意你的app获取⻨克⻛的数据 // 其他时候调⽤⽅法的时候,则不会提醒⽤户 // ⽽会传递之前的值来要求⽤户同意 [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { if (granted) { // ⽤户同意获取数据 } else { // 可以显示⼀个提示框告诉⽤户这个app没有得到允许? } }]; 你同时还要注意,如果你在获得⽤户的同意之前使⽤任何⽅法来使⽤⻨克⻛的话,会引起 iOS系统弹出以下警示栏: 五、[NSArray firstObject]的实现 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 126iOS6、7、8、9新特性汇总和适配说明-[NSArray firstObject]可能是Objective-C中被调⽤做多的API。在Open Radar上⼀个简单 的调查显示有⼀些需求苹果已经做了记录。好消息是现在这些需求已经得到了解决。. firstObject的使⽤可以追溯到iOS4.0,但是那时仅仅是⼀个私有⽅法。在iOS7以前,⼯程 师⽤下⾯的⽅式来使⽤它: NSArray *arr = @[]; id item = [arr firstObject]; // 在之前你需要做以下⼯作 id item = [arr count] > 0 ? arr[0] : nil; 因为上⾯的⽅式很平常,有些⼈将它作为⼀个类增加到NSArray中,然后创建他们⾃⼰的 firstObject⽅法。 这个⽅法的问题是这个⽅法的名字必须是唯⼀的,否则的话这个⽅法所引发的问题⽆法预 估。 请确保检查你是否有任何⾃定义的代码在NSArray上实现了firstObject,如果有的话看看 它是否是必须的,不是必须的话就把它全部移除。 六、增加了instancetype instancetype让iOS7API变得更加难懂。苹果改变了⼤部分 initializer和简易构造函数 (convenience constructors),⽤instancetype代替id作返回类型。但是这个 instancetype是什么呢? instancetype⽤来在声明⼀个⽅法时告诉编译器其返回类型,它表示返回调⽤该⽅法的类 的对象。 这⽐之前返回id的通常做法要好,编译器可以对返回类型做⼀些检查,如果出现错误,在 编译时就能提醒你,⽽不是在程序运⾏时发⽣崩溃。 同时,在调⽤⼦类⽅法时,使⽤它还可以省去对返回值的强制类型转换,编译器能够正确 推断⽅法的返回值类型。 要说到instancetaype的缺点和优点吗?基本上,在任何可能的情况下都可以使⽤它。 七、设置UIImage的渲染模式:UIImage.renderingMode 着⾊(Tint Color)是iOS7界⾯中的⼀个重⼤改变,你可以设置⼀个UIImage在渲染时是 否使⽤当前视图的Tint Color。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 127iOS6、7、8、9新特性汇总和适配说明UIImage新增了⼀个只读属性:renderingMode,对应的还有⼀个新增⽅法: imageWithRenderingMode:,它使⽤UIImageRenderingMode枚举值来设置图⽚的 renderingMode属性。该枚举中包含下列值: // 根据图⽚的使⽤环境和所处的绘图上下⽂⾃动调整渲染模式 UIImageRenderingModeAutomatic // 始终绘制图⽚原始状态,不使⽤Tint Color UIImageRenderingModeAlwaysOriginal // 始终根据Tint Color绘制图⽚,忽略图⽚的颜⾊信息 UIImageRenderingModeAlwaysTemplate renderingMode属性的默认值是UIImageRenderingModeAutomatic,即UIImage是否使⽤ Tint Color取决于它显示的位置。其他情况可以看下⾯的图例: 以下的代码说明了使⽤⼀个既定的rendering模式创建图⽚是多么简单: UIImage *img = [UIImage imageNamed:@"myimage"]; img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 128iOS6、7、8、9新特性汇总和适配说明⼋、tintcolor VS barTintColor iOS7中你可以使⽤⼀个给定的颜⾊,甚⾄是记⼊颜⾊主题来给整个app着⾊,帮助你的 app脱颖⽽出。设置app的tint color很简答,只要使⽤UIView的新属性tintColor即可。 这个属性是否听上去很熟悉呢?应该很熟悉,有些类,⽐如说UINaviagtionBar, UISearchBar,UITabBar以及UIToolbar已经有了这么命名的属性。他们现在有了⼀个新 的属性:barTintColor。 为了避免使⽤新属性的时候犯错误,如果你的appp需要⽀持iOS6以前的系统的时候,请 检查⼀下。 UINavigationBar *bar = self.navigationController.navigationBar; UIColor *color = [UIColor greenColor]; if ([bar respondsToSelector:@selector(setBarTintColor:)]) { // iOS 7+ bar.barTintColor = color; } else { // what year is this? 2012? bar.tintColor = color; } 九、去掉了纹理颜⾊ 纹理颜⾊?对,不再使⽤他们了,不能再创建可以展现纹理的颜⾊。 根据UIInterface.h⽂件中的注释,-[UIColor groupTableViewBackgroundColor]应该是要在 iOS6当中即被删除了,但是它仅仅只是不像之前那样返回纹理颜⾊了。然⽽,以下的颜⾊ 在iOS7当中被删除了: + (UIColor *)viewFlipsideBackgroundColor; + (UIColor *)scrollViewTexturedBackgroundColor; + (UIColor *)underPageBackgroundColor; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 129iOS6、7、8、9新特性汇总和适配说明⼗、UIButtonTypeRoundRect被UIButtonTypeSystem取代了 在iOS开发刚开始就陪伴着你的⽼朋友现在也被删除了,它就是UIButtonTypeRoundRect ,被新的UIButtonTypeSystem取代了。 如果每次iOS系统的发布都没有⼀些新的功能会是什么样⼦?这些新功能相信⼤部分开发 者已经知道了,你可能会发现⼀些新颖的⽅式将它们整合到你的app中去! ⼗⼀、检查⽆线路由是否可⽤ 定制⼀个视频播放器的能⼒在iOS版本每次的发布中⼀直有所进步。⽐如说,在iOS6之 前,你不能在MPVolumeView中改变AirPlay的icon。 在iOS7当中,你可以通过AirPlay,蓝⽛或是其他的虚线机制了解是否有⼀个远程的设备 可⽤。了解它的话,就可以让你的app在恰当的时候做恰当的事,⽐如说,在没有远程设 备的时候就不显示AirPlay的icon。 以下是新增加到MPVolumeView的新属性和推送 @property (nonatomic, readonly) BOOL wirelessRoutesAvailable; // 是否有设备可以连接的⽆线线路? @property (nonatomic, readonly) BOOL wirelessRouteActive; // 设备现在是否连接上了⽹络 NSString *const MPVolumeViewWirelessRoutesAvailableDidChangeNotification; NSString *const MPVolumeViewWirelessRouteActiveDidChangeNotification; ⼗⼆、了解蜂窝⽹络 在iOS7之前,是使⽤Reachability来检测设备是否连接到WWAN或是Wifi的。iOS7在这个 基础上更进了⼀步,它会告诉你的设备连接上的是那种蜂窝⽹络,⽐如说是Edge⽹络, HSDPA⽹络,或是LTE⽹络。告诉⽤户他们连接上的是哪种⽹络可以优化⽤户体验,因 为这样他们会知道⽹速如何,不会去请求需要⾼⽹速的⽹络请求。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 130iOS6、7、8、9新特性汇总和适配说明这是CTTelephonyNetworkInfo的部分功能,它是CoreTelephony框架的⼀部分。iOS7还 增加了currentRadioAccessTechnology属性和 CTRadioAccessTechnologyDidChangeNotification到这个类。还有⼀些新的字符串常量 来定义可能的值,⽐如说是CTRadioAccessTechnologyLTE。 以下代码告诉你在app delegate中如何使⽤这个新功能: @import CoreTelephony.CTTelephonyNetworkInfo; // new modules syntax! @interface AppDelegate () // we need to keep a reference to the CTTelephonyNetworkInfo object, otherwise the notifications won't be fired! @property (nonatomic, strong) CTTelephonyNetworkInfo *networkInfo; @end @implementation ViewController - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // whatever stuff your method does... self.networkInfo = [[CTTelephonyNetworkInfo alloc] init]; NSLog(@"Initial cell connection: %@", self.networkInfo.currentRadioAccessTechnology); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessChanged) name: CTRadioAccessTechnologyDidChangeNotification object:nil]; // whatever stuff your method does... } - (void)radioAccessChanged { NSLog(@"Now you're connected via %@", self.networkInfo.currentRadioAccessTechnology); } @end 注意:研究⼀下CTTelephonyNetworkInfo.h ⽂件来看看是否有其他⽆线⽹络类型的的字 符串常量。如果设备没有连上的话,currentRadioAccessTechnology 则会返回nil。 ⼗三、通过iCloud同步⽤户设备的密码 iOS7以及Mavericks增加了iCloud Keychain来提供密码,以及iCloud中⼀些敏感数据的同 步。开发者可以通过keychain中的kSecAttrSynchronizable key来遍历dictionary对象。 由于直接处理keychain⽐较难,封装库提供了⼀个简单的处理keychain的⽅法。 SSKeychain封装库可能是最有名的的⼀个,作为⼀种福利,现在它⽀持在iCloud同步。 以下代码⽚段显示了如何使⽤SSKeychain: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 131iOS6、7、8、9新特性汇总和适配说明#import - (BOOL)saveCredentials:(NSError **)error { SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; query.password = @"MySecretPassword"; query.service = @"MyAwesomeService"; query.account = @"John Doe"; query.synchronizable = YES; return [query save:&error]; } - (NSString *)savedPassword:(NSError **)error { SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; query.service = @"MyAwesomeService"; query.account = @"John Doe"; query.synchronizable = YES; query.password = nil; if ([query fetch:&error]) { return query.password; } return nil; } 不要忘记CocoaPods是快速便捷安装SSKeychian的好⽅法。 ⼗四、使⽤NSAttributedString显示HTML 在app中使⽤webview有时会让⼈⾮常沮丧,即使只是显示少量的HTMLneirong ,webview 也会消耗⼤量的内存。现在iOS7让这些变得简单了,你可以从⽤少量代码在HTML⽂件中 创建⼀个NSAttributedString,⽐如: NSString *html = @"Wow! Now iOS can create

NSAttributedString

from HTMLs!"; NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}; NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:nil error:nil]; 现在你可以在任意的UIKit对象上使⽤NSAttributedString 了,⽐如说是⼀个UILabel或是⼀ 个UITextField。 注意:NSHTMLTextDocumentType 只是NSDocumentTypeDocumentAttribute key⼀种 可能的值。你还可以使⽤NSPlainTextDocumentType,NSRTFTextDocumentType或是 NSRTFDTextDocumentType。 你还可以从NSAttributedString中创建⼀个HTML字符串,如下: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 132iOS6、7、8、9新特性汇总和适配说明NSAttributedString *attrString; // from previous code NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}; NSData *htmlData = [attrString dataFromRange:NSMakeRange(0, [attrString length]) documentAttributes:options error:nil]; NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding]; 现在你估计在app中会更多的使⽤HTML了。 ⼗五、使⽤原⽣的Base64 Base64是使⽤ASCII码显示⼆进制数据的⼀种流⾏⽅法。直到现在,开发者还不得不使⽤ 开源的⼯具来编码解码Base64的内容。 现在iOS7引⼊了以下四种新的NSData⽅法来操作Base64编码的数据: // From NSData.h - (id)initWithBase64EncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options; - (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options; - (id)initWithBase64EncodedData:(NSData *)base64Data options:(NSDataBase64DecodingOptions)options; - (NSData *)base64EncodedDataWithOptions:(NSDataBase64EncodingOptions)options; 这些⽅法可以帮助你轻易的将NSData对象转化为Base64,或者将Base64转化为NSData object。⻅以下的例⼦: NSData* sampleData = [@"Some sample data" dataUsingEncoding:NSUTF8StringEncoding]; NSString * base64String = [sampleData base64EncodedStringWithOptions:0]; NSLog(@"Base64-encoded string is %@", base64String); // prints "U29tZSBzYW1wbGUgZGF0YQ==" NSData* dataFromString = [[NSData alloc] initWithBase64EncodedString:base64String options:0]; NSLog(@"String is %@",[NSString stringWithUTF8String:[dataFromString bytes]]); // prints "String is Some sample data" 如果你需要⽀持iOS6或者更早以前的系统,你可以使⽤以下两个⽅法: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 133iOS6、7、8、9新特性汇总和适配说明/* These methods first appeared in NSData.h on OS X 10.9 and iOS 7.0. They are deprecated in the same releases in favor of the methods in the NSDataBase64Encoding category. However, these methods have existed for several releases, so they may be used for applications targeting releases prior to OS X 10.9 and iOS 7.0. */ - (id)initWithBase64Encoding:(NSString *)base64String; - (NSString *)base64Encoding; ⼗六、使⽤UIApplicationUserDidTakeScreenshotNotification来检查截图 在iOS7之前,像Snapshot或是Facebook Poke这样的app是使⽤⼀些很精巧的⽅法来检测 ⽤户是否有截图。然⽽,iOS7提供⼀个崭新的推送⽅法: UIApplicationUserDidTakeScreenshotNotification。只要像往常⼀样订阅即可知道什么时 候截图了。 注意:UIApplicationUserDidTakeScreenshotNotification 将会在截图完成之后显示。现在 在截图截取之前⽆法得到通知。希望苹果会在iOS8当中增加 UIApplicationUserWillTakeScreenshotNotification。 ⼗七、实现多语⾔语⾳合成 如果可以让app说话会不会很好呢?iOS7加⼊了两个新类:AVSpeechSynthesizer 以及 AVSpeechUtterance。这两个类可以给你的app发声。很有意思不是吗?有多种语⾔可供 选择——Siri不会说的语⾔也有,⽐如说巴⻄葡萄⽛语。 使⽤这两个类给app提供语⾔合成的功能⾮常简单。AVSpeechUtterance 代表你想说什 么,如何说。AVSpeechSynthesizer ⽤来发出这些声⾳,⻅以下代码⽚段: AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init]; AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"Wow, I have such a nice voice!"]; utterance.rate = AVSpeechUtteranceMaximumSpeechRate / 4.0f; utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"en-US"]; // defaults to your system language [synthesizer speakUtterance:utterance]; ⼗⼋、使⽤了新的UIScreenEdgePanGestureRecognizer UIScreenEdgePanGestureRecognizer 继承⾃UIPanGestureRecognizer ,它可以让你从 屏幕边界即可检测⼿势。 使⽤新的⼿势识别器很简单,⻅以下: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 134iOS6、7、8、9新特性汇总和适配说明UIScreenEdgePanGestureRecognizer *recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgeRecognizer:)]; recognizer.edges = UIRectEdgeLeft; [self.view addGestureRecognizer:recognizer]; ⼗九、使⽤UIScrollViewKeyboardDismissMode实现了Message app的⾏为 像Messages app⼀样在滚动的时候可以让键盘消失是⼀种⾮常好的体验。然⽽,将这种 ⾏为整合到你的app很难。幸运的是,苹果给UIScrollView添加了⼀个很好⽤的属性 keyboardDismissMode,这样可以⽅便很多。 现在仅仅只需要在Storyboard中改变⼀个简单的属性,或者增加⼀⾏代码,你的app可以 和办到和Messages app⼀样的事情了。 这个属性使⽤了新的UIScrollViewKeyboardDismissMode enum枚举类型。这个enum枚举 类型可能的值如下: UIScrollViewKeyboardDismissModeNone // the keyboard is not dismissed automatically when scrolling UIScrollViewKeyboardDismissModeOnDrag // dismisses the keyboard when a drag begins UIScrollViewKeyboardDismissModeInteractive // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss 以下是让键盘可以在滚动的时候消失需要设置的属性: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 135iOS6、7、8、9新特性汇总和适配说明⼆⼗、使⽤Core Image来检测眨眼以及微笑 iOS给Core Image增加了两种⼈脸检测功能:CIDetectorEyeBlink以及CIDetectorSmile。 这也就是说你现在可以在照⽚中检测微笑以及眨眼。 以下是在app中使⽤它的⽅法: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 136iOS6、7、8、9新特性汇总和适配说明UIImage *image = [UIImage imageNamed:@"myImage"]; CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}]; NSDictionary *options = @{ CIDetectorSmile: @YES, CIDetectorEyeBlink: @YES }; NSArray *features = [detector featuresInImage:image.CIImage options:options]; for (CIFaceFeature *feature in features) { NSLog(@"Bounds: %@", NSStringFromCGRect(feature.bounds)); if (feature.hasSmile) { NSLog(@"Nice smile!"); } else { NSLog(@"Why so serious?"); } if (feature.leftEyeClosed || feature.rightEyeClosed) { NSLog(@"Open your eyes!"); } } ⼆⼗⼀、给UITextView增加了链接 现在在iOS添加你⾃⼰的Twitter账户更加简单了,现在你可以给⼀个NSAttributedString增 加链接了,然后当它被点击的时候唤起⼀个定制的action。 ⾸先,创建⼀个NSAttributedString然后增加给它增加⼀个NSLinkAttributeName 属性,⻅ 以下: NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"This is an example by @marcelofabri_"]; [attributedString addAttribute:NSLinkAttributeName value:@"username://marcelofabri_" range:[[attributedString string] rangeOfString:@"@marcelofabri_"]]; NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor greenColor], NSUnderlineColorAttributeName: [UIColor lightGrayColor], NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)}; // assume that textView is a UITextView previously created (either by code or Interface Builder) textView.linkTextAttributes = linkAttributes; // customizes the appearance of links textView.attributedText = attributedString; textView.delegate = self; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 137iOS6、7、8、9新特性汇总和适配说明这样就可以让链接在⽂本中显示。然⽽,你也可以控制当链接被点击的时候会发⽣什么, 实现这个可以使⽤UITextViewDelegate协议的新的shouldInteractWithURL⽅法,就像这 样: - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange { if ([[URL scheme] isEqualToString:@"username"]) { NSString *username = [URL host]; // do something with this username // ... return NO; } return YES; // let the system open this URL } iOS8新特性 ⼀、UIAlertController对alert&actionSheet的封装 UIAlertController.h 提示框按钮的选择 typedef NS_ENUM(NSInteger, UIAlertActionStyle) { UIAlertActionStyleDefault = 0, UIAlertActionStyleCancel, UIAlertActionStyleDestructive } NS_ENUM_AVAILABLE_IOS(8_0); 提示框的样式 typedef NS_ENUM(NSInteger, UIAlertControllerStyle) { UIAlertControllerStyleActionSheet = 0, UIAlertControllerStyleAlert } NS_ENUM_AVAILABLE_IOS(8_0); NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertAction : NSObject iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 138iOS6、7、8、9新特性汇总和适配说明创建提示框按钮 + (instancetype)actionWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(UIAlertAction *action))handler; @property (nonatomic, readonly) NSString *title; @property (nonatomic, readonly) UIAlertActionStyle style; @property (nonatomic, getter=isEnabled) BOOL enabled; @end NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertController : UIViewController 创建提示框 + (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle; 添加按钮 - (void)addAction:(UIAlertAction *)action; @property (nonatomic, readonly) NSArray *actions; 添加⽂本输⼊框 - (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler; @property (nonatomic, readonly) NSArray *textFields; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *message; @property (nonatomic, readonly) UIAlertControllerStyle preferredStyle; 简单实⽤示例: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 139iOS6、7、8、9新特性汇总和适配说明// 1.创建提示框对象,默认是actionSheet效果 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"注意" message:@"我的呈现⽅式变了" preferredStyle:UIAlertControllerStyleAlert]; // 2.创建取消按钮并添加到提示框上 [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { NSLog(@"取消按钮被点击了"); }]]; // 3.呈现提示框 [self presentViewController:alert animated:YES completion:nil]; ⼆、UIPopoverController直接通过present⽅式呈现 UIViewController.h typedef NS_ENUM(NSInteger, UIModalPresentationStyle) { UIModalPresentationFullScreen = 0, UIModalPresentationPageSheet NS_ENUM_AVAILABLE_IOS(3_2), UIModalPresentationFormSheet NS_ENUM_AVAILABLE_IOS(3_2), UIModalPresentationCurrentContext NS_ENUM_AVAILABLE_IOS(3_2), UIModalPresentationCustom NS_ENUM_AVAILABLE_IOS(7_0), UIModalPresentationOverFullScreen NS_ENUM_AVAILABLE_IOS(8_0), UIModalPresentationOverCurrentContext NS_ENUM_AVAILABLE_IOS(8_0), UIModalPresentationPopover NS_ENUM_AVAILABLE_IOS(8_0), UIModalPresentationNone NS_ENUM_AVAILABLE_IOS(7_0) = -1, }; @property (nonatomic,readonly) UIPopoverPresentationController *popoverPresentationController NS_AVAILABLE_IOS(8_0); 使⽤示例: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 140iOS6、7、8、9新特性汇总和适配说明// 1.创建内容控制器 UITableViewController *contentVc = [[UITableViewController alloc] init]; // 2.1 设置呈现⽅式 contentVc.modalPresentationStyle = UIModalPresentationPopover; // 2.2设置在导航栏的左边按钮呈现 contentVc.popoverPresentationController.barButtonItem = self.navigationItem.leftBarButtonItem; // 3.呈现 [self presentViewController:contentVc animated:YES completion:nil]; 以前的⽅式: // 1.创建内容控制器 UITableViewController *contentVc = [[UITableViewController alloc] init]; // 2.创建popover UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:contentVc]; popover.popoverContentSize = CGSizeMake(100, 100); // 3.呈现 [popover presentPopoverFromBarButtonItem:self.navigationItem.leftBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 三、获取⽤户授权的⽤户隐私保护 地图定位示例 : iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 141iOS6、7、8、9新特性汇总和适配说明// 导⼊定位框架 #import @interface ViewController () // 设置定位对象 @property(nonatomic,strong)CLLocationManager* maneger; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 当使⽤iOS8定位的时候需要请求⽤户授权,且在info.plist⾥添加字段NSLocationAlwaysUsageDescription 请求⽤户授权的描述 // iOS7仅仅需要在info.plist⾥添加字段Privacy - Location Usage Description 请求⽤户授权的描述 // 不需要再写下⾯的代码 if (IOS8) { [self.maneger requestAlwaysAuthorization];//请求⽤户授权 } // 开启定位 [self.maneger startUpdatingLocation]; } 四、针对屏幕适配应运⽽⽣的size classes size classes是为了解决storyboard只能订制⼀种屏幕样式的问题,它不再是具体的尺⼨, ⽽是抽象尺⼨通过宽/⾼ 的compact、any、regular 组成了九种组合包含了所有苹果设备 的尺⼨。 iOS9新特性 ⼀、⽹络适配 iOS9系统发送的⽹络请求将统⼀使⽤TLS 1.2 SSL。采⽤TLS 1.2 协议,⽬的是强制增强 数据访问安全,⽽且系统Foundation框架下的相关⽹络请求,将不再默认使⽤HTTP等不 安全的⽹络协议,⽽默认采⽤TLS 1.2。服务器因此需要更新,以解析相关数据。如不更 新,可通过在 info.plist 中声明,倒退回不安全的⽹络请求。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 142iOS6、7、8、9新特性汇总和适配说明什么是SSL/TLS?跟HTTP和HTTPS有什么关系? 跟往常⼀样,先说结论: HTTP + SSL/TLS + TCP = HTTPS TLS 是 SSL 新的别称。举个例⼦: “TLS1.0”之于“SSL3.1”,犹“公元2015”之于“⺠国104”,或者是“⼀千克”之于“⼀公⽄”,或 者是“半⽄”之于“⼋两”:称呼不同,但意思相同。 SSL 3.0版本之后的迭代版本被重新命名为TLS 1.0,也就是说: TLS 1.0 = SSL 3.1 所以他们是⼀个东⻄,我们平常也经常简单⻅到 “SSL/TLS” 这种说法。常⽤的是下⾯这 些: SSL 2.0 SSL 3.0 TLS 1.0 (SSL 3.1) TLS 1.1 (SSL 3.1) TLS 1.2 (SSL 3.1) 那为什么标题是“使⽤HTTPS”⽽没有提及SSL和TLS什么事? 要理解这个,要看下⼀个公 式: HTTP + SSL/TLS + TCP = HTTPS 打个⽐⽅:如果原来的 HTTP 是塑料⽔管,容易被戳破;那么如今新设计的 HTTPS 就像 是在原有的塑料⽔管之外,再包⼀层⾦属⽔管。⼀来,原有的塑料⽔管照样运⾏;⼆来, ⽤⾦属加固了之后,不容易被戳破。 ⽬前,应⽤最⼴泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的⽀持。Apple让你的HTTP采⽤SSL/TLS协议,就是让你从HTTP转到HTTPS。 以前的HTTP不是也能⽤吗?为什么要⽤SSL/TLS,闲得慌?!Apple是不是⼜在反⼈类? 不使⽤SSL/TLS的HTTP通信,就是不加密的通信! iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 143iOS6、7、8、9新特性汇总和适配说明所有信息明⽂传播,带来了三⼤⻛险: 窃听⻛险(eavesdropping):第三⽅可以获知通信内容。 篡改⻛险(tampering):第三⽅可以修改通信内容。 冒充⻛险(pretending):第三⽅可以冒充他⼈身份参与通信。 SSL/TLS协议是为了解决这三⼤⻛险⽽设计的,希望达到: 所有信息都是加密传播,第三⽅⽆法窃听。 具有校验机制,⼀旦被篡改,通信双⽅会⽴刻发现。 配备身份证书,防⽌身份被冒充。 如何适配?---弱弱地问下:加班要多久? 正如⽂章开头所说: TLS 1.2 协议 强制增强数据访问安全 系统 Foundation 框架下的相关⽹络请求,将不再默 认使⽤ HTTP 等不安全的⽹络协议,⽽默认采⽤ TLS 1.2。服务器因此需要更新,以解析 相关数据。如不更新,可通过在 Info.plist 中声明,倒退回不安全的⽹络请求。 ⽅案⼀:⽴即让公司的服务端升级使⽤TLS 1.2。 ⽅案⼆:虽Apple不建议,但可通过在 Info.plist 中声明,倒退回不安全的⽹络请求依然能 让App访问指定http,甚⾄任意的http。 info.plist 配置中的XML源码如下所示: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 144iOS6、7、8、9新特性汇总和适配说明上⾯是⽐较严谨的做法,指定了能访问哪些特定的HTTP。当然也有暴⼒的做法: 彻底倒 退回不安全的HTTP⽹络请求,能任意进⾏HTTP请求,⽐如你在开发⼀款浏览器App,或 者你想偷懒,或者后台想偷懒,或者公司不给你升级服务器。但⽬前Apple的官⽅⽂档并 未提及如何在 info.plist 配置可以参考本⽂:http://blog.6ag.cn/1065.html ⼆、更灵活的后台定位 如果不适配iOS9,就不能偷偷在后台定位。不过苹果将允许出现这种场景: 同⼀App中的多个location manager,⼀些只能在前台定位,另⼀些可在后台定位,并可 随时开启或者关闭特定location manager的后台定位。 如何偷偷在后台定位: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 145iOS6、7、8、9新特性汇总和适配说明// 1. 实例化定位管理器 _locationManager = [[CLLocationManager alloc] init]; // 2. 设置代理 _locationManager.delegate = self; // 3. 定位精度 [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; // 4.请求⽤户权限:分为:?只在前台开启定位?在后台也可定位, //注意:建议只请求?和?中的⼀个,如果两个权限都需要,只请求?即可, //??这样的顺序,将导致bug:第⼀次启动程序后,系统将只请求?的权限,?的权限系统不会请求,只会在下⼀次启动应⽤时请求? if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) { //[_locationManager requestWhenInUseAuthorization];//?只在前台开启定位 [_locationManager requestAlwaysAuthorization];//?在后台也可定位 } // 5.iOS9新特性:将允许出现这种场景:同⼀app中多个location manager:⼀些只能在前台定位,另⼀些可在后台定位(并可随时禁⽌其后台定位)。 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) { _locationManager.allowsBackgroundLocationUpdates = YES; } // 6. 更新⽤户位置 [_locationManager startUpdatingLocation]; 但是如果照着这种⽅式尝试,⽽没有配置info.plist,100%你的程序会崩溃掉,并报错: * Assertion failure in -[CLLocationManager setAllowsBackgroundLocationUpdates:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/CoreLocationFramework_Sim/CoreL ocation-1808.1.5/Framework/CoreLocation/CLLocationManager.m:593 要将 info.plist 配置如下: 对应的 Info.plist 的XML源码是: iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 146iOS6、7、8、9新特性汇总和适配说明三、Bitcode bitcode的理解应该是把程序编译成的⼀种过渡代码,然后苹果再把这个过渡代码编译成可 执⾏的程序。bitcode也允许苹果在后期重新优化我们程序的⼆进制⽂件,有类似于App瘦 身的思想。未来Watch应⽤须包含Bitcode,iOS不强制,但Xcode7默认会开启Bitcode。 ⽤了xcode7的编译器编译之前没问题的项⽬可能会出现下列报错。 XXXX’ does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode forthistarget. forarchitecture arm64 问题的原因是:某些第三⽅库还不⽀持bitcode。要不然是等待库的开发者升级了此项功能 我们更新库,要不就是把这个bitcode禁⽤。禁⽤Bitcode,⽅法⻅下图: 四、企业级分发 iOS9之前,企业级分发⼗分⽅便:点击App出现“信任按钮”。 iOS9以后,企业级分发ipa包将遭到与Mac上dmg安装包⼀样的待遇。默认不能安装,也 不再出现“信任按钮”,必须让⽤户进⾏gif图中的设置。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 147iOS6、7、8、9新特性汇总和适配说明五、URL scheme URL scheme⼀般使⽤的场景是应⽤程序有分享或跳其他平台授权的功能,分享或授权后 再跳回来。在iOS8并没有做过多限制,在iOS9中,如果使⽤URL scheme必须 在"info.plist"中将你要在外部调⽤的URL scheme列为⽩名单,否则不能使⽤。 canOpenURL: failed forURL : "mqzone://qqapp"- error: "This app is not allowed to query for scheme mqzone" 具体的解决⽅案也是要在info.plist中设置 LSApplicationQueriesSchemes 类型为数组,下 ⾯添加所有你⽤到的scheme iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 148iOS6、7、8、9新特性汇总和适配说明推荐⼀篇博客: http://awkwardhare.com/post/121196006730/quick-take-on-ios-9-url- scheme-changes 其中最关键的是以下部分: If you call the “canOpenURL” method on a URL that is not in your whitelist, it will return “NO”, even if there is an app installed that has registered to handle this scheme. A “This app is not allowed to query for scheme xxx” syslog entry will appear. If you call the “openURL” method on a URL that is not in your whitelist, it will fail silently. A “This app is not allowed to query for scheme xxx” syslog entry will appear. 六、新字体 iOS8中,字体是Helvetica,中⽂的字体有点类似于“华⽂细⿊”。只是苹果⼿机⾃带渲染, 所以看上去可能⽐普通的华⽂细⿊要美观。iOS9中,中⽂系统字体变为了专为中国设计 的“苹⽅” 有点类似于⼀种word字体“幼圆”。字体有轻微的加粗效果,并且最关键的是字体 间隙变⼤了! 所以很多原本写死了width的label可能会出现“...”的情况。 上⾯这两张图也可以直观的看出同⼀个界⾯,同⼀个label的变化。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 149iOS6、7、8、9新特性汇总和适配说明所以为了在界⾯显示上不出错,就算是固定⻓度的⽂字也还是建议使⽤sizetofit 或者ios向 上取整 ceilf() 或者提前计算。 CGSize size = [title sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14.0f]}]; CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height)); 七、tableview 虽然现在的iOS9已经推送正式版了,但是iOS9使⽤时还是会感觉到App⽐以前更加卡顿 了,tableView拖动时卡顿显示的最为明显。 并且之前遇到⼀个bug,原本好的项⽬⽤ xcode7⼀编译,tableView刷新出了问题 ,[tableView reloadData]⽆效,有⼀⾏cell明明 改变了但是刷新不出来。 感觉可能是这个⽅法和某种新加的特性冲突了,猜测可能是 reloadData的操作被推迟到下⼀个RunLoop执⾏最终失效。 解决的⽅法是,注释[tableView reloadData],改⽤局部刷新,问题居然就解决了。 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone]; ⼋、iPad适配Slide Over 和 Split View iPad适配Slide Over 和 Split View,若想适配multi tasking特性,唯⼀的建议: 弃纯代码,改⽤storyboard、xib,纵观苹果WWDC所有Demo均是如此。 Mysteries of Auto Layout, Part 1 What's New in Storyboards Implementing UI Designs in Interface Builder Getting Started with Multitasking on iPad in iOS 9 Optimizing Your App for Multitasking on iPad in iOS iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 150iOS6、7、8、9新特性汇总和适配说明SQLite数据库框架--FMDB FMDB概述 什么是FMDB FMDB是iOS平台的SQLite数据库框架 FMDB以OC的⽅式封装了SQLite的C语⾔API FMDB的优点 使⽤起来更加⾯向对象,省去了很多麻烦、冗余的C语⾔代码 对⽐苹果⾃带的Core Data框架,更加轻量级和灵活 提供了多线程安全的数据库操作⽅法,有效地防⽌数据混乱 FMDB的github地址 https://github.com/ccgus/fmdb FMDB基本使⽤ FMDB有三个核⼼类 FMDatabase ⼀个FMDatabase对象就代表⼀个单独的SQLite数据库 ⽤来执⾏SQL语句 FMResultSet 使⽤FMDatabase执⾏查询后的结果集 FMDatabaseQueue iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 151SQLite数据库框架--FMDB⽤于在多线程中执⾏多个查询或更新,它是线程安全的 FMDB打开数据库 通过指定SQLite数据库⽂件路径来创建FMDatabase对象 FMDatabase *db = [FMDatabase databaseWithPath:path]; if (![db open]) { NSLog(@"数据库打开失败!"); } ⽂件路径(path)有三种情况: 具体⽂件路径 如果不存在会⾃动创建 空字符串@"" 会在临时⽬录创建⼀个空的数据库 当FMDatabase连接关闭时,数据库⽂件也被删除 nil 会创建⼀个内存中临时数据库 当FMDatabase连接关闭时,数据库会被销毁 执⾏更新 在FMDB中,除查询以外的所有操作,都称为“更新”create、drop、insert、update、 delete等 使⽤executeUpdate:⽅法执⾏更新 - (BOOL)executeUpdate:(NSString*)sql, ... - (BOOL)executeUpdateWithFormat:(NSString*)format, ... - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments 示例 [db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"] 执⾏查询 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 152SQLite数据库框架--FMDB查询⽅法 - (FMResultSet *)executeQuery:(NSString*)sql, ... - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments 示例 // 查询数据 FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"]; // 遍历结果集 while ([rs next]) { NSString *name = [rs stringForColumn:@"name"]; int age = [rs intForColumn:@"age"]; double score = [rs doubleForColumn:@"score"]; } FMDatabaseQueue FMDatabase这个类是线程不安全的,如果在多个线程中同时使⽤⼀个FMDatabase 实例,会造成数据混乱等问题. 为了保证线程安全,FMDB提供⽅便快捷的FMDatabaseQueue类 FMDatabaseQueue的创建 FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path]; 简单使⽤ [queue inDatabase:^(FMDatabase *db) { [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"]; [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"]; [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"]; FMResultSet *rs = [db executeQuery:@"select * from t_student"]; while ([rs next]) { // … } }]; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 153SQLite数据库框架--FMDB使⽤事务 [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"]; [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"]; [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"]; FMResultSet *rs = [db executeQuery:@"select * from t_student"]; while ([rs next]) { // … } }]; 事务回滚 rollback = YES; iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 154SQLite数据库框架--FMDBiOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 155第三⽅框架SDWebImage SDWebImage是⼀个很厉害的图⽚缓存的框架。既ASIHttp+AsyncImage之后,我⼀直 使⽤AFNetworking集成的UIImageView+AFNetworking.h,但后者对于图⽚的缓存实际 应⽤的是NSURLCache⾃带的cache机制。⽽NSURLCache每次都要把缓存的raw data 再转化为UIImage,就带来了数据处理和内存⽅⾯的更多操作。具体的⽐较在这⾥。 SDWebImage提供了如下三个category来进⾏缓存。 • MKAnnotationView(WebCache) • UIButton(WebCache) • UIImageView(WebCache) 以最为常⽤的UIImageView为例: 1. UIImageView+WebCache: setImageWithURL:placeholderImage:options: 先显示 placeholderImage ,同时由SDWebImageManager 根据 URL 来在本地查找图⽚。 2. SDWebImageManager: downloadWithURL:delegate:options:userInfo: SDWebImageManager是将UIImageView+WebCache同SDImageCache链接起来的 类, SDImageCache: queryDiskCacheForKey:delegate:userInfo:⽤来从缓存根据 CacheKey查找图⽚是否已经在缓存中 3. 如果内存中已经有图⽚缓存, SDWebImageManager会回调 SDImageCacheDelegate : imageCache:didFindImage:forKey:userInfo: 4. ⽽ UIImageView+WebCache 则回调SDWebImageManagerDelegate: webImageManager:didFinishWithImage:来显示图⽚。 5. 如果内存中没有图⽚缓存,那么⽣成 NSInvocationOperation 添加到队列,从硬盘查 找图⽚是否已被下载缓存。 6. 根据 URLKey 在硬盘缓存⽬录下尝试读取图⽚⽂件。这⼀步是在 NSOperation 进⾏ 的操作,所以回主线程进⾏结果回调 notifyDelegate:。 7. 如果上⼀操作从硬盘读取到了图⽚,将图⽚添加到内存缓存中(如果空闲内存过⼩, 会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进⽽回调展示图⽚。 8. 如果从硬盘缓存⽬录读取不到图⽚,说明所有缓存都不存在该图⽚,需要下载图⽚, 回调 imageCache:didNotFindImageForKey:userInfo:。 9. 共享或重新⽣成⼀个下载器 SDWebImageDownloader 开始下载图⽚。 10. 图⽚下载由 NSURLConnection 来做,实现相关 delegate 来判断图⽚下载中、下载 完成和下载失败。 11. connection:didReceiveData: 中利⽤ ImageIO 做了按图⽚下载进度加载效果。 12. connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图⽚解 码处理。 13. 图⽚解码处理在⼀个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对 下载的图⽚进⾏⼆次处理,最好也在这⾥完成,效率会好很多。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 156SDWebImage14. 在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成, imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。 15. imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图⽚下 载完成。 16. 通知所有的 downloadDelegates 下载完成,回调给需要的地⽅展示图⽚。 17. 将图⽚保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。 18. 写⽂件到硬盘在单独 NSInvocationOperation 中完成,避免拖慢主线程。 19. 如果是在iOS上运⾏,SDImageCache 在初始化的时候会注册notification 到 UIApplicationDidReceiveMemoryWarningNotification 以及 UIApplicationWillTerminateNotification,在内存警告的时候清理内存图⽚缓存,应⽤结 束的时候清理过期图⽚。 20. SDWebImagePrefetcher 可以预先下载图⽚,⽅便后续使⽤ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 157SDWebImage其他 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 158其他HR⼈事⾯试常⻅问题 请你⾃我介绍⼀下你⾃⼰? 回答提示:⼀般⼈回答这个问题过于平常,只说姓名、年龄、爱好、⼯作经验,这些在简 历上都有。其实,企业最希望知道的是求职者能否胜任⼯作,包括:最强的技能、最深⼊ 研究的知识领域、个性中最积极的部分、做过的最成功的事,主要的成就等,这些都可以 和学习⽆关,也可以和学习有关,但要突出积极的个性和做事的能⼒,说得合情合理企业 才会相信。 企业很重视⼀个⼈的礼貌,求职者要尊重考官,在回答每个问题之后都说⼀ 句“谢谢”,企业喜欢有礼貌的求职者。 你觉得你个性上最⼤的优点是什么? 回答提示:沉着冷静、条理清楚、⽴场坚定、顽强向上、乐于助⼈和关⼼他⼈、适应能⼒ 和幽默感、乐观和友爱。 说说你最⼤的缺点? 回答提示:这个问题企业问的概率很⼤,通常不希望听到直接回答的缺点是什么等,如果 求职者说⾃⼰⼩⼼眼、爱忌妒⼈、⾮常懒、脾⽓⼤、⼯作效率低,企业肯定不会录⽤你。 绝对不要⾃作聪明地回答“我最⼤的缺点是过于追求完美”,有的⼈以为这样回答会显得⾃ ⼰⽐较出⾊,但事实上,他已经岌岌可危了。业喜欢求职者从⾃⼰的优点说起,中间加⼀ 些⼩缺点,最后再把问题转回到优点上,突出优点的部分,企业喜欢聪明的求职者。 你对加班的看法? 回答提示:实际上好多公司问这个问题,并不证明⼀定要加班,只是想测试你是否愿意为 公司奉献。 回答样本:如果是⼯作需要我会义不容辞加班,我现在单身,没有任何家庭 负担,可以全身⼼的投⼊⼯作。但同时,我也会提⾼⼯作效率,减少不必要的加班。 你对薪资的要求? 回答提示:如果你对薪酬的要求太低,那显然贬低⾃⼰的能⼒;如果你对薪酬的要求太 ⾼,那⼜会显得你分量过重,公司受⽤不起。⼀些雇主通常都事先对求聘的职位定下开⽀ 预算,因⽽他们第⼀次提出的价钱往往是他们所能给予的最⾼价钱,他们问你只不过想证 实⼀下这笔钱是否⾜以引起你对该⼯作的兴趣。如果你⾃⼰必须说出具体数⽬,请不要说 ⼀个宽泛的范围,那样你将只能得到最低限度的数字。最好给出⼀个具体的数字,这样表 明你已经对当今的⼈才市场作了调查,知道像⾃⼰这样学历的雇员有什么样的价值。 回 答样本⼀:我对⼯资没有硬性要求,我相信贵公司在处理我的问题上会友善合理。我注重 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 159HR⼈事⾯试常⻅问题的是找对⼯作机会,所以只要条件公平,我则不会计较太多。 回答样本⼆:我受过系统 的软件编程的训练,不需要进⾏⼤量的培训,⽽且我本⼈也对编程特别感兴趣。因此,我 希望公司能根据我的情况和市场标准的⽔平,给我合理的薪⽔。 你的职业规划? 回答提示:这是每⼀个应聘者都不希望被问到的问题,但是⼏乎每个⼈都会被问到,⽐较 多的答案是“管理者”。但是近⼏年来,许多公司都已经建⽴了专⻔的技术途径。这些⼯作 地位往往被称作“顾问”、“参议技师”或“⾼级软件⼯程师”等等。当然,说出其他⼀些你感兴 趣的职位也是可以的,⽐如产品销售部经理,⽣产部经理等⼀些与你的专业有相关背景的 ⼯作。要知道,考官总是喜欢有进取⼼的应聘者,此时如果说“不知道”,或许就会使你丧 失⼀个好机会。最普通的回答应该是“我准备在技术领域有所作为”或“我希望能按照公司的 管理思路发展”。 你还有什么问题要问吗? 回答提示:企业的这个问题看上去可有可⽆,其实很关键,企业不喜欢说“没问题”的⼈, 因为其很注重员⼯的个性和创新能⼒。企业不喜欢求职者问个⼈福利之类的问题,如果有 ⼈这样问:贵公司对新⼊公司的员⼯有没有什么培训项⽬,我可以参加吗?或者说贵公司 的晋升机制是什么样的?企业将很欢迎,因为体现出你对学习的热情和对公司的忠诚度以 及你的上进⼼。 如果通过这次⾯试我们单位录⽤了你,但⼯作⼀段时间却发现你根本不适合这个职 位,你怎么办? 回答提示:⼀段时间发现⼯作不适合我,有两种情况:①如果你确实热爱这个职业,那你 就要不断学习,虚⼼向领导和同事学习业务知识和处事经验,了解这个职业的精神内涵和 职业要求,⼒争减少差距;②你觉得这个职业可有可⽆,那还是趁早换个职业,去发现适 合你的,你热爱的职业,那样你的发展前途也会⼤点,对单位和个⼈都有好处。 在完成某项⼯作时,你认为领导要求的⽅式不是最好的,⾃⼰还有更好的⽅法,你应 该怎么做? 回答提示:①.原则上我会尊重和服从领导的⼯作安排,同时私底下找机会以请教的⼝ 吻,婉转地表达⾃⼰的想法,看看领导是否能改变想法。②如果领导没有采纳我的建议, 我也同样会按领导的要求认真地去完成这项⼯作。③.还有⼀种情况,假如领导要求的⽅ 式违背原则,我会坚决提出反对意⻅,如领导仍固执⼰⻅,我会毫不犹豫地再向上级领导 反映。 如果你的⼯作出现失误,给本公司造成经济损失,你认为该怎么办? iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 160HR⼈事⾯试常⻅问题回答提示:①我本意是为公司努⼒⼯作,如果造成经济损失,我认为⾸要的问题是想⽅设 法去弥补或挽回经济损失。如果我⽆能⼒负责,希望单位帮助解决。②分清责任,各负其 责,如果是我的责任,我⽢愿受罚;如果是⼀个我负责的团队中别⼈的失误,也不能幸灾 乐祸,作为⼀个团队,需要互相提携共同完成⼯作,安慰同事并且帮助同事查找原因总结 经验。 ③总结经验教训,⼀个⼈的⼀⽣不可能不犯错误,重要的是能从⾃⼰的或者是别 ⼈的错误中吸取经验教训,并在今后的⼯作中避免发⽣同类的错误。检讨⾃⼰的⼯作⽅ 法、分析问题的深度和⼒度是否不够,以致出现了本可以避免的错误。 谈谈你对跳槽的看法? 回答提示:①正常的“跳槽”能促进⼈才合理流动,应该⽀持。②频繁的跳槽对单位和个⼈ 双⽅都不利,应该反对。 ⼯作中你难以和同事、上司相处,你该怎么办? 回答提示:①我会服从领导的指挥,配合同事的⼯作。②我会从⾃身找原因,仔细分析是 不是⾃⼰⼯作做得不好让领导不满意,同事看不惯。还要看看是不是为⼈处世⽅⾯做得不 好,如果是这样的话 我会努⼒改正。③如果我找不到原因,我会找机会跟他们沟通,请 他们指出我的不⾜,有问题就及时改正。④作为优秀的员⼯,应该时刻以⼤局为重,即使 在⼀段时间内,领导和同事对我不理解,我也会做好本职⼯作,虚⼼向他们学习,我相 信,他们会看⻅我在努⼒,总有⼀天会对我微笑的。 你对于我们公司了解多少? 回答提示:在去公司⾯试前上⽹查⼀下该公司主营业务。如回答:贵公司有意改变策略, 加强与国外⼤⼚的OEM合作,⾃有品牌的部分则透过海外经销商。 请说出你选择这份⼯作的动机? 回答提示:这是想知道⾯试者对这份⼯作的热忱及理解度,并筛选因⼀时兴起⽽来应试的 ⼈,如果是⽆经验者,可以强调“就算职种不同,也希望有机会发挥之前的经验”。 你最擅⻓的技术⽅向是什么? 回答提示:说和你要应聘的职位相关的课程,表现⼀下⾃⼰的热诚没有什么坏处。 你能为我们公司带来什么呢? 回答提示:企业很想知道未来的员⼯能为企业做什么,求职者应再次重复⾃⼰的优势,然 后说:“就我的能⼒,我可以做⼀个优秀的员⼯在组织中发挥能⼒,给组织带来⾼效率和 更多的收益”。企业喜欢求职者就申请的职位表明⾃⼰的能⼒,⽐如申请营销之类的职 位,可以说:“我可以开发⼤量的新客户,同时,对⽼客户做更全⾯周到的服务,开发⽼ 客户的新需求和消费。”等等。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 161HR⼈事⾯试常⻅问题最能概括你⾃⼰的三个词是什么? 回答提示:我经常⽤的三个词是:适应能⼒强,有责任⼼和做事有始终,结合具体例⼦向 主考官解释, 为什么要离职? 回答提示:回答这个问题时⼀定要⼩⼼,就算在前⼀个⼯作受到再⼤的委屈,对公司有多 少的怨⾔,都千万不要表现出来,尤其要避免对公司本身主管的批评,避免⾯试官的负⾯ 情绪及印象。建议此时最好的回答⽅式是将问题归咎在⾃⼰身上,例如觉得⼯作没有学习 发展的空间,⾃⼰想在⾯试⼯作的相关产业中多加学习,或是前⼀份⼯作与⾃⼰的⽣涯规 划不合等等,回答的答案最好是积极正⾯的。 回答样本:我希望能获得⼀份更好的⼯ 作,如果机会来临,我会抓住。我觉得⽬前的⼯作,已经达到顶峰,即沒有升迁机会。 对⼯作的期望与⽬标何在? 回答提示:这是⾯试者⽤来评断求职者是否对⾃⼰有⼀定程度的期望、对这份⼯作是否了 解的问题。对于⼯作有确实学习⽬标的⼈通常学习较快,对于新⼯作⾃然较容易进⼊状 况,这时建议你,最好针对⼯作的性质找出⼀个确实的答案,如业务员的⼯作可以这样回 答:“我的⽬标是能成为⼀个超级业务员,将公司的产品⼴泛的推销出去,达到最好的业 绩成效;为了达到这个⽬标,我⼀定会努⼒学习,⽽我相信以我认真负责的态度,⼀定可 以达到这个⽬标。”其他类的⼯作也可以⽐照这个⽅式来回答,只要在⽬标⽅⾯稍微修改 ⼀下就可以了。 就你申请的这个职位,你认为你还⽋缺什么? 回答提示:企业喜欢问求职者弱点,但精明的求职者⼀般不直接回答。他们希望看到这样 的求职者:继续重复⾃⼰的优势,然后说:“对于这个职位和我的能⼒来说,我相信⾃⼰ 是可以胜任的,只是缺乏经验,这个问题我想我可以进⼊公司以后以最短的时间来解决, 我的学习能⼒很强,我相信可以很快融⼊公司的企业⽂化,进⼊⼯作状态。”企业喜欢能 够巧妙地躲过难题的求职者。 你通常如何处理別⼈的批评? 回答提示:①沈默是⾦,不必说什么,否则情况更糟,不过我会接受建设性的批评。②我 会等⼤家冷靜下来再讨论。 怎样对待⾃⼰的失敗? 回答提示:我们⼤家⽣来都不是⼗全⼗美的,我相信我有第⼆个机会改正我的错误。 什么会让你有成就感? 回答提示:为贵公司竭⼒效劳,尽我所能,完成⼀个项⽬。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 162HR⼈事⾯试常⻅问题你为什么愿意到我们公司来⼯作? 回答提示:对于这个问题,你要格外⼩⼼,如果你已经对该单位作了研究,你可以回答⼀ 些详细的原因,像“公司本身的⾼技术开发环境很吸引我。”、“我同公司出⽣在同样的时 代,我希望能够进⼊⼀家与我共同成⻓的公司。”、“你们公司⼀直都稳定发展,在近⼏年 来在市场上很有竞争⼒。”、“我认为贵公司能够给我提供⼀个与众不同的发展道路。”这都 显示出你已经做了⼀些调查,也说明你对⾃⼰的未来有了较为具体的远景规划。 你和别⼈发⽣过争执吗?你是怎样解决的? 回答提示:这是⾯试中最险恶的问题,其实是考官布下的⼀个陷阱,千万不要说任何⼈的 过错,应知成功解决⽭盾是⼀个协作团体中成员所必备的能⼒。假如你⼯作在⼀个服务⾏ 业,这个问题简直成了最重要的⼀个环节。你是否能获得这份⼯作,将取决于这个问题的 回答。考官希望看到你是成熟且乐于奉献的。他们通过这个问题了解你的成熟度和处世能 ⼒。在没有外界⼲涉的情况下,通过妥协的⽅式来解决才是正确答案。 对这项⼯作,你有哪些可预⻅的困难? 回答提示:①不宜直接说出具体的困难,否则可能令对⽅怀疑应聘者不⾏。②可以尝试迂 回战术,说出应聘者对困难所持有的态度——⼯作中出现⼀些困难是正常的,也是难免 的,但是只要有坚忍不拔的毅⼒、良好的合作精神以及事前周密⽽充分的准备,任何困难 都是可以克服。 分析:⼀般问这个问题,⾯试者的希望就⽐较⼤了,因为已经在谈⼯作 细节,但常规思路中的回答,⼜被⾯试官“骗”了。当⾯试官询问这个问题的时候,有两个 ⽬的。第⼀,看看应聘者是不是在⾏,说出的困难是不是在这个职位中⼀般都不可避免的 问题。第⼆,是想看⼀下应聘者解决困难的⼿法对不对,及公司能否提供这样的资源。⽽ 不是想了解应聘者对困难的态度。 如果我录⽤你,你将怎样开展⼯作? 回答提示: ①如果应聘者对于应聘的职位缺乏⾜够的了解,最好不要直接说出⾃⼰开展 ⼯作的具体办法。②可以尝试采⽤迂回战术来回答,如“⾸先听取领导的指示和要求,然 后就有关情况进⾏了解和熟悉,接下来制定⼀份近期的⼯作计划并报领导批准,最后根据 计划开展⼯作。”。 分析:这个问题的主要⽬的也是了解应聘者的⼯作能⼒和计划性、条 理性,⽽且重点想要知道细节。如果向思路中所讲的迂回战术,⾯试官会认为回避问题, 如果引导了⼏次仍然是回避的话,此⼈绝对不会录⽤了。 在完成某项⼯作时,你认为领导要求的⽅式不是最好的,⾃⼰还有更好的⽅法,你应 该怎么做?与上级意⻅不⼀是,你将怎么办? 回答提示:①.原则上我会尊重和服从领导的⼯作安排;同时私底下找机会以请教的⼝ 吻,婉转地表达⾃⼰的想法,看看领导是否能改变想法。②如果领导没有采纳我的建议, 我也同样会按领导的要求认真地去完成这项⼯作。③.还有⼀种情况,假如领导要求的⽅ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 163HR⼈事⾯试常⻅问题式违背原则,我会坚决提出反对意⻅,如领导仍固执⼰⻅,我会毫不犹豫地再向上级领导 反映。 你⼯作经验⽋缺,如何能胜任这项⼯作? 常规思路:①如果招聘单位对应届毕业⽣的应聘者提出这个问题,说明招聘公司并不真正 在乎“经验”,关键看应聘者怎样回答。②对这个问题的回答最好要体现出应聘者的诚恳、 机智、果敢及敬业。③如“作为应届毕业⽣,在⼯作经验⽅⾯的确会有所⽋缺,因此在读 书期间我⼀直利⽤各种机会在这个⾏业⾥做兼职。我也发现,实际⼯作远⽐书本知识丰 富、复杂。但我有较强的责任⼼、适应能⼒和学习能⼒,⽽且⽐较勤奋,所以在兼职中均 能圆满完成各项⼯作,从中获取的经验也令我受益⾮浅。请贵公司放⼼,学校所学及兼职 的⼯作经验使我⼀定能胜任这个职位。” 点评:这个问题思路中的答案尚可,突出⾃⼰的 吃苦能⼒和适应性以及学习能⼒(不是学习成绩)为好。 您在前⼀家公司的离职原因是什么? 回答提示:①最重要的是:应聘者要使找招聘单位相信,应聘者在过往的单位的“离职原 因”在此家招聘单位⾥不存在。②避免把“离职原因”说得太详细、太具体。③不能掺杂主观 的负⾯感受,如“太⾟苦”、“⼈际关系复杂”、“管理太混乱”、“公司不重视⼈才”、“公司排斥 我们某某的员⼯”等。④但也不能躲闪、回避,如“想换换环境”、“个⼈原因”等。⑤不能涉 及⾃⼰负⾯的⼈格特征,如不诚实、懒惰、缺乏责任感、不随和等。⑥尽量使解释的理由 为应聘者个⼈形象添彩。⑦相关例⼦:如“我离职是因为这家公司倒闭;我在公司⼯作了 三年多,有较深的感情;从去年始,由于市场形势突变,公司的局⾯急转直下;到眼下这 ⼀步我觉得很遗憾,但还要⾯对显示,重新寻找能发挥我能⼒的舞台。”同⼀个⾯试问题 并⾮只有⼀个答案,⽽同⼀个答案并不是在任何⾯试场合都有效,关键在应聘者掌握了规 律后,对⾯试的具体情况进⾏把握,有意识地揣摩⾯试官提出问题的⼼理背景,然后投其 所好。 分析:除⾮是薪资太低,或者是最初的⼯作,否则不要⽤薪资作为理由。“求发 展”也被考官听得太多,离职理由要根据每个⼈的真实离职理由来设计,但是在回答时⼀ 定要表现得真诚。实在想不出来的时候,家在外地可以说是因为家中有事,须请假⼏个 ⽉,公司⼜不可能准假,所以辞职,这个答案⼀般⾯试官还能接受。 为了做好你⼯作份外之事,你该怎样获得他⼈的⽀持和帮助? 回答提示:每个公司都在不断变化发展的过程中,你当然希望你的员⼯也是这样。你希望 得到那些希望并欢迎变化的⼈,因为这些⼈明⽩,为了公司的发展,变化是公司⽇常⽣活 中重要组成部分。这样的员⼯往往很容易适应公司的变化,并会对变化做出积极的响应。 **如果你在这次⾯试中没有被录⽤,你怎么打算? 回答提示:现在的社会是⼀个竞争的社会,从这次⾯试中也可看出这⼀点,有竞争就必然 有优劣,有成功必定就会有失败。往往成功的背后有许多的困难和挫折,如果这次失败了 也仅仅是⼀次⽽已,只有经过经验经历的积累才能塑造出⼀个完全的成功者。我会从以下 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 164HR⼈事⾯试常⻅问题⼏个⽅⾯来正确看待这次失败:①要敢于⾯对,⾯对这次失败不⽓馁,接受已经失去了这 次机会就不会回头这个现实,从⼼理意志和精神上体现出对这次失败的抵抗⼒。要有⾃ 信,相信⾃⼰经历了这次之后经过努⼒⼀定能⾏,能够超越⾃我。②善于反思,对于这次 ⾯试经验要认真总结,思考剖析,能够从⾃身的⻆度找差距。正确对待⾃⼰,实事求是地 评价⾃⼰,辩证的看待⾃⼰的⻓短得失,做⼀个明⽩⼈。③⾛出阴影,要克服这⼀次失败 带给⾃⼰的⼼理压⼒,时刻牢记⾃⼰弱点,防患于未然,加强学习,提⾼⾃身素质。④认 真⼯作,回到原单位岗位上后,要实实在在、踏踏实实地⼯作,三⼗六⾏、⾏⾏出状元, 争取在本岗位上做出⼀定的成绩。⑤再接再厉,成为国家公务员⼀直是我的梦想,以后如 果有机会我仍然后再次参加竞争。 谈谈你过去做过的成功案例?(⼯作中遇到什么问题) 回答提示:举⼀个你最有把握的例⼦,把来⻰去脉说清楚,⽽不要说了很多却没有重点。 切忌夸⼤其词,把别⼈的功劳到说成⾃⼰的,很多主管为了确保要⽤的⼈是最适合的,会 打电话向你的前⼀个主管征询对你的看法及意⻅,所以如果说谎,是很容易穿梆的。 如何安排⾃⼰的时间?会不会排斥加班? 回答提示:基本上,如果上班⼯作有效率,⼯作量合理的话,应该不太需要加班。可是我 也知道有时候很难避免加班,加上现在⼯作都采⽤责任制,所以我会调配⾃⼰的时间,全 ⼒配合。 分析:虽然不会有⼈⼼⽢情愿的加班,但依旧要表现出⾼配合度的诚意。 这个职务的期许? 回答提示:希望能借此发挥我的所学及专⻓,同时也吸收贵公司在这⽅⾯的经验,就公 司、我个⼈⽽⾔,缔造“双赢”的局⾯。 分析:回答前不妨先询问该公司对这项职务的责任 认定及归属,因为每⼀家公司的状况不尽相同,以免说了⼀堆理想抱负却发现⽜头不对⻢ 嘴。 什么选择我们这家公司? 回答提示:曾经在报章杂志看过关于贵公司的报道,与⾃⼰所追求的理念有志⼀同。⽽贵 公司在业界的成绩也是有⽬共睹的,⽽且对员⼯的教育训练、升迁等也都很有制度。 分 析:去⾯试前先做功课,了解⼀下该公司的背景,让对⽅觉得你真的很有⼼想得到这份⼯ 作,⽽不只是探探路。 谈谈如何适应办公室⼯作的新环境? 回答提示:①办公室⾥每个⼈有各⾃的岗位与职责,不得擅离岗位。②根据领导指示和⼯ 作安排,制定⼯作计划,提前预备,并按计划完成。③多请示并及时汇报,遇到不明⽩的 要虚⼼请教。④抓间隙时间,多学习,努⼒提⾼⾃⼰的政治素质和业务⽔平。 ⼯作中学习到了些什么? iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 165HR⼈事⾯试常⻅问题回答提示:这是针对转职者提出的问题,建议此时可以配合⾯试⼯作的特点作为主要依据 来回答,如业务⼯作需要与⼈沟通,便可举出之前⼯作与⼈沟通的例⼦,经历了哪些困 难,学习到哪些经验,把握这些要点做陈述,就可以轻易过关了。 除了本公司外,还应聘了哪些公司? 回答提示:很奇怪,这是相当多公司会问的问题,其⽤意是要概略知道应徵者的求职志 向,所以这并⾮绝对是负⾯答案,就算不便说出公司名称,也应回答“销售同种产品的公 司”,如果应聘的其他公司是不同业界,容易让⼈产⽣⽆法信任的感觉。 何时可以到职? 回答提示:⼤多数企业会关⼼就职时间,最好是回答“如果被录⽤的话,到职⽇可按公司 规定上班”,但如果还未辞去上⼀个⼯作、上班时间⼜太近,似乎有些强⼈所难,因为交 接⾄少要⼀个⽉的时间,应进⼀步说明原因,录取公司应该会通融的。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 166HR⼈事⾯试常⻅问题pch⽂件的作⽤ .pch 表示 precompiled header 这是⼀个你⼯程要⽤到的来⾃于外部框架的头⽂件列表。xcode将编译这些头到⽂件,这 将减少你在选择Build 或Build and Go时编译项⽬的时间。通常⽤到的头⽂件已经⾃动包 含了pch,系统编译每个cpp⽂件前,都会先include这个⽂件。这样就节省了添加include 的时间,相当于加速编译 还有就是可以再这⾥⾯放⼊宏,在整个⼯程中都可以⽤ iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 167pch⽂件的作⽤ATS 应⽤传输安全(Xcode7之后不能访问⽹络解决⽅案) ATS 应⽤传输安全(App Transport Security) ATS 是iOS9和OS X El Capitan的⼀个新特性。⽬的是提⾼应⽤的安全性。 基于HTTP传输数据的⽹络请求都是明⽂。不⾔⽽喻的这会引起相当⼤的安全⻛险。 Apple强调每个开发者都应该致⼒于保证客户的数据都是安全的,尽管那些数据可能 看起来并不是很重要或者很敏感。 开启App Transport Security后,⽹络传输⾃动通过HTTPS传输⽽不是HTTP. App Transport Security要求TLS (Transport Layer Security) 1.2或者更⾼。它是⼀系 列加密协议的集合⽤来加强在⽹络连接上的安全性。 Xcode 配置 强制访问(可以访问任何⽹址) NSAppTransportSecurity NSAllowsArbitraryLoads iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 168ATS 应⽤传输安全(Xcode7之后不能访问⽹络解决⽅案)Xcode 7免证书真机调试 在Xcode 7中,苹果改变了⾃⼰在许可权限上的策略,此前 Xcode只开放给注册开发者下载,但Xcode 7改变了这种惯有 的做法,⽆需注册开发者账号,仅使⽤普通的Apple ID就能下 载和上⼿体验。此前开发者需每年⽀付99美元的费⽤成为注册 开发者才能在iPhone和iPad真机上运⾏代码,苹果新的开发者 计划则放宽要求,⽆需购买,只要你感兴趣同样可以在设备上 测试app。   如果你打算向App Store提交应⽤,那仍然需要付费。   使⽤⽅法:   1.新建⼀个普通的项⽬   2.进⼊xcode,菜单栏选择xcode –> preferences (快捷键 command + ) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 169Xcode 7免证书真机调试  3.在Accounts选项卡添加⾃⼰的Apple ID。   添加完成后你会看到这样的信息。   可以看到下⾯显示了iOS和Mac的Free标记了,在这之前是没有这些标记的。   4.⽣成证书。   点击View Details。会出现图⼀的样式。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 170Xcode 7免证书真机调试  点中间的“+”号按钮,弹出菜单中选择iOS Development,然后稍等⽚刻(正常情况 下),Xcode就会帮你⽣成好Dev模式需要的certificate了。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 171Xcode 7免证书真机调试  5.在项⽬target的General⻚的Team中选中刚才Apple ID对应的项。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 172Xcode 7免证书真机调试  6.添加Provisioning Profile。   在刚才选择Team的下⾯弹出的Issue下⾯,点Fix。⼀切就都由Xcode搞定了。   7.运⾏。   运⾏的时候这⾥可能会再⼿机上出现⼀个“不受信任的开发者”的提示。 iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 173Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 174Xcode 7免证书真机调试  “设置” –“通⽤” –“描述⽂件”(iOS9.2中为 描述⽂件与设备管理 ) iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 175Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 176Xcode 7免证书真机调试  “开发者账号” iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 177Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 178Xcode 7免证书真机调试  “信任开发者账号” iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 179Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 180Xcode 7免证书真机调试  “信任”    iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 181Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 182Xcode 7免证书真机调试  最后就能跑起来啦!!! iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 183Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 184Xcode 7免证书真机调试iOS⾯试宝典——传智播客·⿊⻢程序员武汉中⼼ 就业部出品 185Xcode 7免证书真机调试
还剩184页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 2 人已下载

下载pdf

pdf贡献者

tao333

贡献于2017-08-08

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf