面试知识点总汇
Objc
一.三大特性
1.封装_点语法
1> 本质
协议,重写copyWithZone方法
3.全局&静态变量
1.全局变量和静态变量的区别
1> 修饰符
全局变量在声明源文件之外使用,需要extern引用一下;
静态变量使用static来修饰
2> 存储地址
两者都是存储在静态存储区,非堆栈上,它们与局部变量的存储分开
3> 生命周期
两者都是在程序编译或加载时由系统自动分配的,程序结束时消亡
4> 外部可访问性
全局变量在整个程序的任何地方均可访问,而静态变量相当于面向对象中的私有变量,他的可访问性只限定于声明它的那个源文件,即作用于仅局限于本文件中
五.runtime/消息转发机制
1.runtime http://www.cocoachina.com/ios/20150715/12540.html
1> 什么是runtime
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者,objc_msgSend
2> runtime干什么用,使用场景
runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法现实的, 不好实现)
在程序运行过程中, 动态创建一个类(比如KVO的底层实现) objc_allocateClassPair,class_addIvar,objc_registerClassPair
在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法(修改封装的框架) objc_setAssociatedObject object_setIvar
遍历一个类的所有成员变量(属性)\所有方法(字典转模型,归解档) class_copyIvarList class_copyPropertyList class_copyMethodList
2.消息机制
1> 消息转发的原理
当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的类,然后在类的调度表(dispatch table)中查找selector。如果无法找到selector,objc_msgSend通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找selector,以此类推直到NSObject类。一旦查找到selector,objc_msgSend方法根据调度表的内存地址调用该实现。 通过这种方式,message与方法的真正实现在执行阶段才绑定。
为了保证消息发送与执行的效率,系统会将全部selector和使用过的方法的内存地址缓存起来。每个类都有一个独立的缓存,缓存包含有当前类自己的 selector以及继承自父类的selector。查找调度表(dispatch table)前,消息发送系统首先检查receiver对象的缓存。
缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点点点。
2> SEL isa super cmd 是什么
sel: 一种类型,表示方法名称,类似字符串(可互转)
isa:在方法底层对应的objc_msgSend调用时,会根据isa找到对象所在的类对象,类对象中包含了调度表(dispatch table),该表将类的sel和方法的实际内存地址关联起来
super_class:每一个类中还包含了一个super_class指针,用来指向父类对象
_cmd在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对象实例
IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数.说白了IMP就是实现方法
3> 动态绑定
—在运行时确定要调用的方法
动态绑定将调用方法的确定也推迟到运行时。在编译时,方法的 调用并不和代码绑定在一起,只有在消实发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术,您的代码每次执行都可以得到不同的结果。运行时因 子负责确定消息的接收者和被调用的方法。运行时的消息分发机制为动态绑定提供支持。当您向一个动态类型确定了的对象发送消息时,运行环境系统会通过接收者 的isa指针定位对象的类,并以此为起点确定被调用的方法,方法和消息是动态绑定的。而且,您不必在Objective-C 代码中做任何工作,就可以自动获取动态绑定的好处。您在每次发送消息时,特别是当消息的接收者是动态类型已经确定的对象时,动态绑定就会例行而透明地发生。
六.内存管理
1.内存区域
1>堆和栈的区别
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈是向低地址扩展的数据结构,是一块连续的内存的区域,栈顶的地址和栈的最大容量是系统预先规定好的,能从栈获得的空间较小。
堆是向高地址扩展的数据结构,是不连续的内存区域,因为系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存,因此堆获得的空间比较灵活,也比较大。
碎片问题:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
2> iOS内存区域
2.1> 栈区
由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.
2.2> 堆区
一般由程序员分配释放,若程序员不释放,程序结束时由系统回收
2.3> 全局区(静态区)
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量相邻的另一块区域.
全局区分为未初始化全局区: .bss段 和初始化全局区: data段.
2.4> 常量区
常量字符串就是放在常量区
2.5> 代码区
存放函数体的二进制代码
2. 字符串的内存管理
创建字符串的内存空间 堆 常量区
3. 你是如何优化内存管理
1> 使用ARC
2> 延迟加载 懒加载
3> 重用 在正确的地方使用reuseIndentifier
4> 缓存 NSCache 保存计算数据
5> 处理内存警告 移除对缓存,图片 object 和其他一些可以重创建的 objects 的强引用
5.1> app delegate 中使用 `applicationDidReceiveMemoryWarning:` 的方法
5.2> 自定义 UIViewController 的子类 (subclass) 中覆盖 `didReceiveMemoryWarning`
5.3> 在自定义类中注册并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
6> 重用大开销对象 NSDateFormatter 和 NSCalendar 懒加载/单例 _formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy”; 设置和创建速度一样慢
7> 自动释放池 手动添加自动释放池
8> 是否缓存图片 imageNamed imageWithContentOfFile
9> 混编
10> 循环引用 delegate block nstimer
11> 移除 kvo nsnotificationcenter 并未强引用,只记录内存地址,野指针报错 UIViewController自动移除 一般在dealloc中
13> performselector 延迟操作 [NSObject cancelPreviousPerformRequestsWithTarget:self]
4. 循环引用
delegate属性的内存策略
block循环引用 实际场景
5. autorelease的使用
1> 工厂方法为什么不释放对象
很多类方法为了在代码块结束时引用的对象不会因无强引用而被释放内存采用自动释放的方式,当其最近的自动释放池释放时该对象才会释放.
2> ARC下autorelease的使用场景
ARC中手动添加autoreleasepool可用于提前释放使用自动释放策略的对象,防止大量自动释放的对象堆积造成内存峰值过高.
3> 自动释放池如何工作
自动释放池时栈结构,每个线程的runloop运行时都会自动创建自动释放池,程序员可以代码手动创建自动释放池,自动释放的对象会被添加到最近的(栈顶)自动释放池中,系统自动创建的自动释放池在每个运行循环结束时销毁释放池并给池中所有对象发release消息,手动创建释放池在所在代码块结束时销毁释放池并发消息统一release
避免内存峰值
SDWebimage中加载gif图片 大循环
栈结构 栈顶
统一发release消息
5> ARC和MRC的混用
5.1> MRC>ARC
把MRC的代码转换成ARC的代码,删除内存管理操作(手动)
xcode提供了自动将MRC转换成ARC的功能,操作菜单栏edit -> Refacotor(重构) -> Convert to Objective-C ARC
5.2> ARC>MRC
在ARC项目中继续使用MRC编译的类,在编译选项中标识MRC文件即可"-fno-objc-arc"
在MRC项目中继续使用ARC编译的类在编译选项中标识MRC文件即可"-fobjc-arc”
6> NSTimer的内存管理
以下代码有什么问题?
、-is(只针对布尔值有效)或者-get的访问器方法,如果有可能,就是用这些方法返回值;
检查是否存在名为-set:的方法,并使用它做设置值。对于 -get和 -set:方法,将大写Key字符串的第一个字母,并与Cocoa的方法命名保持一致;
②如果上述方法不可用,则检查名为-_、-_is(只针对布尔值有效)、-_get和-_set:方法;
③如果没有找到访问器方法,可以尝试直接访问实例变量。实例变量可以是名为:或_;
④如果仍为找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
2> 什么是键-值,键路径是什么
模型的性质是通过一个简单的键(通常是个字符串)来指定的。视图和控制器通过键来查找相应的属性值。在一个给定的实体中,同一个属性的所有值具有相同的数据类型。键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。
键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的性质是由先前的性质决定的,接下来每个键的值也是相对于其前面的性质。键路径使您可以以独立于模型实现的方式指定相关对象的性质。通过键路径,您可以指定对象图中的一
个任意深度的路径,使其指向相关对象的特定属性。
3> 什么是KVC
3> 什么是KVO
4> kvo的实现机制
当某个类的对象第一次被观察时,系统就会在运行时动态地创建该类的一个派生类,在这个派生类中重写原类中被观察属性的setter方法,派生类在被重写的setter方法实现真正的通知机制(Person->NSKVONotifying_Person).
派生类重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的isa指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对setter的调用就会调用重写的setter,从而激活键值通知机制。此外,派生类还重写了dealloc方法来释放资源。
5> KVO计算属性 设置依赖键
监听的某个属性可能会依赖于其它多个属性的变化(类似于swift,可以称之为计算属性),不管所依赖的哪个属性发生了变化,都会导致计算属性的变化,此时该属性如果不能通过set方法来监听(如get中进行计算
//以下代码有什么问题 - (void)setName:(NSString *)name { self.name = name; } - (NSString *)name { return self.name; }点语法的本质是调用类的getter方法和setter方法,如果类中没有getter方法和setter方法就不能使用点语法。 2.继承 1> 如何实现多重继承 消息转发 forwardingTargetForSelector methodSignatureForSelector forwardInvocation delegate和protocol 类别 http://www.cocoachina.com/ios/20130528/6295.html 3.多态 1> 什么是多态 多态:不同对象以自己的方式响应相同的消息的能力叫做多态。 由于每个类都属于该类的名字空间,这使得多态称为可能。类定义中的名字和类定义外的名字并不会冲突。类的实例变量和类方法有如下特点:
- 和C语言中结构体中的数据成员一样,类的实例变量也位于该类独有的名字空间。
- 类方法也同样位于该类独有的名字空间。与C语言中的方法名不同,类的方法名并不是一个全局符号。一个类中的方法名不会和其他类中同样的方法名冲突。两个完全不同的类可以实现同一个方法。
observeValueForKeyPath属于nsobject的分类,且不需要调父类,说明可选实现该方法,没警告可能是编译器规则过滤)
4> 分类的局限性
无法向类中添加新的实例变量,类别没有位置容纳实例变量。
名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。
无法添加实例变量的局限可以使用字典对象解决。
2.extension
3.protocol
三.Foundation
1.字符串
1> 字符串比较
NSString *a = @“hello”; NSString *b = [NSString stringWithFormat:@hello”]; if (a == b){ nslog(@“a==b”); } if ([a isEqualToString: b]){ nslog(@“a isEqualToString b”); }== 比较变量中保存的数值(地址) 速度快 内容同,可能地址不同(常量区,堆区) isEqualTo 比较字符串 非常耗时 2> 字符串截取 截取字符串”20 | http://www.baidu.com”中,”|”字符前面和后面的数据,分别输出它们。
NSString * str = @"20 | http://www.baidu.com"; NSArray *array = [str componentsSeparatedByString:@"|"]; //这是分别输出的截取后的字符串 for (int i = 0; i<[array count]; ++i) { NSLog(@"%d=%@",i,[array objectAtIndex:i]); }3> 格式
NSString *str1 = [NSString stringWithFormat:@"a"b”]; //报错,a”后加b非法 NSString *str2 = [NSString stringWithFormat:@“a""b”]; //显示 ab NSString *str3 = [NSString stringWithFormat:@“a\"b”]; //显示 a”b 反斜杠转义2.NSArray和NSDictionary 1> iOS遍历数组/字典的方法 数组: for循环 for in enumerateObjectsUsingBlock(正序) enumerateObjectsWithOptions:usingBlock:(多一个遍历选项,不保证顺序) 字典:
1. for(NSString *object in [testDic allValues]) 2. for(id akey in [testDic allKeys]){ [sum appendString:[testDic objectForKey:akey]]; } 3. [testDic enumerateKeysAndObjectsUsingBlock:^(idkey,idobj,BOOL*stop) { [sum appendString:obj]; } ];速度: 对于数组, 增强for最快,普通for和block速度差不多,增强最快是因为增强for语法会对容器里的元素的内存地址建立缓冲,遍历的时候直接从缓冲中取元素地址而不是通过调用方法来获取,所以效率高.这也是使用增强for时不能在循环体中修改容器元素的原因之一(可以在循环体中添加标记,在循环体外修改元素) 对于字典,allValues最快,allKey和block差不多,原因是allKey需要做objcetForKey的方法 3.NSValue NSNumber 1> 归档视图尺寸,坐标 4.其他 nil Nil null NSNull 的区别 四.关键字 1.@property 1>readwrite,readonly,assign,retain,copy,nonatomic属性的作用 @property是一个属性访问声明,扩号内支持以下几个属性: 1.1> getter setter getter=getterName,setter=setterName,设置setter与getter的方法名 1.2> weak assign strong copy assign 用于非指针变量。用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id,其setter方法直接赋值,不进行任何retain操作 weak 用于指针变量,比assign多了一个功能,当对象消失后自动把指针变成nil,由于消息发送给空对象表示无操作,这样有效的避免了崩溃(野指针),为了解决原类型与循环引用问题 strong 用于指针变量,setter方法对参数进行release旧值再retain新值 copy 用于指针变量,setter方法进行copy操作,与retain处理流程一样,先旧值release,再copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。 1.3> readwrite,readonly,设置可供访问级别 1.4> nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。所以约定俗成只在主线程更新UI,防止多线程设置UI属性,出现资源抢夺现象 2> 如何避免循环引用 两个对象相互强引用,都无法release,解决办法为一个使用strong,一个使用assign(weak) 3> delegate的属性为什么使用assign/weak 避免出现循环引用,场景如UITableViewController强引用视图UITableView,而该视图的代理又是控制器,为避免循环引用,让delegate为弱引用 2.copy 1> copy的使用场景 当多个指针指向同一个对象时,为避免一个指针对对象的改动对其他指针的使用产生影响,使用copy来创建对象的副本 如页面间传值使用copy,A向B控制器传属性(属性为自定义对象),为避免因A的属性变化对B的属性产生影响 再如多人开发或封装库,在不明确传入值为可变还是不可变的情况下,使用copy更安全 2> 什么是深拷贝浅拷贝 对于非容器类对象,不可变对象进行copy操作为浅拷贝,引用计数器加1,其他三种为深拷贝 对于容器类对象,基本和非容器类对象一致,但注意其深拷贝是对象本身是对象复制,其中元素仍为指针复制,系统将initWithArray方法归为了元素深拷贝,但其实如果元素为不可变元素,仍为指针复制,使用归解档可以实现真正的深拷贝,元素也是对象拷贝NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: array]]; 3> 字符串什么时候使用copy,strong 属性引用的对象由两种情况,可变和不可变字符串 引用对象不可变情况下,copy和strong一样,copy为浅拷贝 引用对象可变情况下,如果希望属性跟随引用对象变化,使用strong,希望不跟随变化使用copy 4> 字符串所在内存区域 @“abc” 常量区 stringwithformat 堆区 5> mutablecopy和copy @property(copy) NSMutableArray *arr;这样写有什么问题 mutablecopy返回可变对象,copy返回不可变对象 6> 如何让自定义类可以使用copy修饰符 实现
@interface SvCheatYourself () { NSTimer *_timer; } @end @implementation SvCheatYourself - (id)init { self = [super init]; if (self) { _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(testTimer:) userInfo:nil repeats:YES]; } return self; } - (void)dealloc { [_timer invalidate]; } - (void)testTimer:(NSTimer*)timer{ NSLog(@"haha!"); } @end
1)timer都会对它的target进行retain,对于重复性的timer,除非手动关闭,否则对象不会释放,场景:导航控制器关联的控制器无法销毁3)timer必须加入到runloop中才会有效,主线程runloop默认开启,异步线程手动启动 4)注意runloop模式 7> ARC的实现原理 在程序预编译阶段,将 ARC 的代码转换为非 ARC 的 代码,自动加入 release、autorelease、retain 3.跨平台 3> OC和C框架对象引用 oc和c 桥接 三个桥接关键字都是干么的 __bridge 不更改归属权 __bridge_transfer 所有权给OC __bridge_retain 解除OC的所有权 ios5/6/7/8 内存方面的区别 ios5.自动引用计数 (ARC) ios6.UICollectionView ( 内存重用机制,图片展示瀑布流实现 ) 在didReceiveMemoryWarning中处理内存(6之前在ViewDidUnload中) http://blog.csdn.net/likendsl/article/details/8199350 ios7.iOS7以后强制使用ARC ios8 4.MRC 七.数据传递 1.block 1> block属性为什么用copy? 栈->堆 2> block使用注意什么? 循环引用 __block 修饰局部变量,这个变量在 block 内外属于同一个地址 上的变量,可以被 block 内部的代码修改 3> block的主要使用场景 ? 动画 数组字典排序遍历 回调状态 错误控制 多线程GCD 4>block原理 block属性是指向结构体的指针, 2.Delegate 4> 什么时候用delegate,什么时候用Notification delegate针对one-to-one关系,并且reciever可以返回值给sender,notification 可以针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到 reciever的某个功能反馈值,notification用于通知多个object某个事件。 5> delegate和block block使代码更紧凑,便于阅读,delegate可以设置必选和可选的方法实现,相比block block可以访存局部变量. 不需要像以前的回调一样,把在操作后所有需要用到的数据封装成特定的数据结构, 你完全可以直接访问局部变量. 3.KVC和KVO 1> 如何调用私有变量 如何修改系统的只读属性 KVC的查找顺序 KVC在某种程度上提供了访问器的替代方案。不过访问器方法是一个很好的东西,以至于只要是有可能,KVC也尽量再访问器方法的帮助下工作。为了设置或者返回对象属性,KVC按顺序使用如下技术: ①检查是否存在-
2)NSTimer要加到异步线程中,防止线程繁忙导致定时器失准
- (NSString *)accountForBank { return [NSString stringWithFormat:@“%@ for %@", self.accountName, self.bankCodeEn]; }),则可以设置依赖键,两种方法:
1>
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; if ([key isEqualToString:@"accountForBank"]) { keyPaths = [keyPaths setByAddingObjectsFromArray:@[@"accountName", @"bankCodeEn"]]; } return keyPaths; }2>
+ (NSSet *)keyPathsForValuesAffectingAccountForBank { return [NSSet setWithObjects:@"accountBalance", @"bankCodeEn", nil]; }6> KVO集合属性 可对可变集合的元素改变进行监听(如添加、删除和替换元素),使用集合监听对象 使用KVO 重写class 5> kvo使用场景 ①实现上下拉刷新控件 contentoffset ②webview混合排版 contentsize ③监听模型属性实时更新UI 4.栈结构&队列 栈结构先进后出,iOS中有navigationcontroller的子控制器,autoreleasepool 队列先进先出, 八.其他 1.int和NSInteger的区别 NSInteger表示当前cpu下整型所占最大字节,不同CPU的long型所占字节不同,32位int4 long4,64位int4,long8 2.import和include import可以避免重复包含 3.@class 避免循环引用头文件 UI 一.控件 1.属性 1> frame和bounds的区别 frame:可表示尺寸和位置,与父视图坐标系的关系,位置以自己的左上角为原点,可用于形变和位移 bounds:可表示尺寸和位置,与自身视图坐标系的关系,大多数情况(滚动视图的子视图等除外)以自己的中心点为原点,可用于形变 center:只表示位置,表示自己中心的坐标,可用于位移 2> trasform 修改位移\形变\旋转,transform不同于board\center\frame,前者中记录的是形变的数据,不发生形变其值是空的,所以我们需要新建结构体,用CGAffineTransform(仿射变换)函数给对象结构体属性赋值,而后者是控件的固有属性,内存数据是始终存在的,当我们用他们做移动等操作时,是改变其值,所以是结构体赋值三步曲,不用CG的函数 使用情景区别: transform一般用于有来有回的变化,而frame是有去无回 2.UIScrollView 1> contentsize、contentoffset、contentinset的区别 内容视图的尺寸 内容视图当前位置相对滚动视图frame的偏移量 内容视图相对滚动视图frame的展示原点 3.UITableview 1> 自定义高度 1.1>新建一个继承自UITableViewCell的类 1.2>重写initWithStyle:reuseIdentifier:方法 1.3>添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中) 1.4>进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片) 1.5>提供2个模型 数据模型: 存放文字数据\图片数据 frame模型: 存放数据模型\所有子控件的frame\cell的高度 1.6>cell拥有一个frame模型(不要直接拥有数据模型) 1.7>重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame 2> 自定义高度原理 A 手动计算 1> 由于heightForRow比cellForRow方法先调用,创建frame模型包含微博模型,重写微博模型赋值set方法,提前计算cell子控件的frame并保存,heightForRow方法中取出frame模型中保存的高度,实现自定义高度cell 2> 设置最大尺寸、文本属性,根据文本内容计算正文内容展示尺寸 3> cellForRow中创建自定义cell包含frame属性,重写frame属性set方法创建cell子控件并赋值frame模型保存的子控件尺寸 B. 自动计算 1> 首先设置行高使用autolayout自动计算并预估高度 2> 在stroboard中对cell内容进行自动布局,注意设置图片距离底部约束,cellForRow中创建storyboard中对应标记的自定义cell 3> 由于正文内容的不确定性,设置label多行,拖线图片高度约束,根据图片有无,设置代码设置高度约束 4.UICollectionView 1> 如何实现瀑布流,流水布局 1.1> 使用UICollectionView 1.2> 使用自定义的FlowLayout 1.3> 需要在layoutAttributesForElementsInRect中设置自定义的布局(item的frame) 1.4> 在 prepareLayout中计算布局 1.5> 遍历数据内容,根据索引取出对应的attributes(使用layoutAttributesForCellWithIndexPath),根据九宫格算法设置布局 1.6> 细节1: 实时布局,重写shouldInvalidateLayoutForBoundsChange(bounds改变重新布局,scrollview的contentoffset>bounds) 1.7> 细节2: 计算设置itemsize(保证内容显示完整,uicollectionview的content size是根据itemize计算的),根据列最大高度/对应列数量求出,最大高度累加得到 1.8> 细节3: 追加item到最短列,避免底部参差不齐. 2> 和UITableView的使用区别 1)必须使用下面的方法进行Cell类的注册:
- (void)registerClass:forCellWithReuseIdentifier: - (void)registerClass:forSupplementaryViewOfKind:withReuseIdentifier: - (void)registerNib:forCellWithReuseIdentifier:2)collectionView与tableView最大的不同点,collectionView必须要使用自己的layout(UICollectionViewhttp://www.cnblogs.com/neworiginou/archive/2012/11/14/2770038.html 6.性能优化 1> 如何进行性能优化 1.1> 内存优化的点 重用 懒加载 1.2> 渲染优化 尽量使用不透明的图 把 views 设置为透明 1.3> 在ImageView设置前,尽量先调整好图片大小 尤其放在uiscrolliview中自动缩放耗能 1.4> 避免使用过大的xib 和分镜的区别 一次性加载 1.5> 不要阻塞主线程 除渲染,触摸响应等 尽量异步处理 如存储,网络 异步线程通知 1.6> 缓存 网络响应,图片,计算结果(行高) 网络响应NSUrlconnection默认缓存request,设置策略 非网络请求 使用nscache nsdictionary 1.7> 避免反复处理数据 在服务器端和客户端使用相同的数据结构 1.8> 选择正确的数据格式 json 速度快 解析方便 xml sax方式逐行解析 解析大文件不占用内存和损失性能 1.9> 优化tableview 重用cell 缓存行高 cell子视图尽量少且不透明 1.10> 选择正确的数据存储选项 plist nscoding NSUserDefaults sqlite coredata 八.算法 1.交换数值的几种方法 中间变量 加减法 异或 2.oc/c实现常用排序 3. 二叉树 链表 写一个单链表,要求可以插入数据和删除单个数据 递归