OC:分类(好处,和延展的区别)block(原理,底层,作用。)代理循环引用(原因,解决)、内存
分类 : 一般用于扩展一个类的方法,它可以不用创建一个新的类,但是不能够扩充成员变量,使用分类重写本类的方法后无法再调用原来的方法,使用分类还能够将一个类的定义写在不同的文件内,可以拆分业务逻辑,使一个分类的功能更专一
延展(extension)延展相当于匿名的分类,一般写在实现文件里面(.m文件),它可以扩充私有变量和方法,但是变量和方法只能在本文件内有效(私有的),其他文件不可以调用。(并且一般不会有人通过延展扩充方法)。
继承 使用继承扩充一个类,需要再创建一个子类,能够扩充成员变量和方法,可以重写父类的方法,而且可以通过super调用父类的方法,但是由于继承于父类.
block
1.保存代码。一段代码在合适的时间执行就调用block(1、请求成功时弹出一个提示框 2、异步执行完之后回调)。
2block一般用来两个的类的数据逆传递(修改昵称,姓名,性别的时候) A-B B往
A传数据。
3.block也可以将一个操作当做函数或方法的参数来传递
代理的循环引用
Delegate使用weak来修饰? 循环引用
例如在tableviewController当中,tableView的Delegate使用weak来修饰,如果使用strong或者copy修饰,delegate作为tableview的一个成员变量,tableViewController会有一个强指针指向tableView,而tableview会有一个强指针指向delegate,这个时候delegate的引用计数就会加1,一般情况下tableview的代理都是指向自己的控制器,因为delegate使用strong修饰,所以delegate会有一个强指针指向tableViewController,tableViewController的引用计数也会加1,tableviewController和delegate创建时引用计数初始化都是1,此时它们的引用计数都是2,再ARC机制下,当控制器移除时,它们的引用计数会自动减1,然后各自的引用计数都是1,就再也不会释放了,这个时候就会照成内存泄露
简单点说:
(在tableViewController中delegate使用strong修饰时,delegate会有一个强指针指向controller,而controller会对内部的delegate做一次retain操作,就会有一个强指针指向delegate,当内存释放是,controller要释放就要等delegate先被释放,而delegate释放要等controller先释放,这个时候谁都无法释放,就造成了循环引用)
内存
在OC当中没有垃圾回收机制(GC),而是使用引用计数 来管理内存的释放,OC中有手动引用计数(_MRC)和自动引用计数(ARC)当oc中的对象使用alloc new 创建时引用计数就会加1,被retain、copy一次引用计数也会加1,当被release 或 autorelease时 引用计数减1,当引用计数下降为0时,该对象的内存就会被释放,对象被销毁
在ARC中我们已经无需再手动管理内存的释放,ARC并不是oc的特性,而是xcode编译器的特性,xcode会自动帮我们加上release 或autorelease等代码
内存优化: 1、懒加载(1、使用时再加载 2、保证对象只创建一次 )
2、复用 轮播 两个imageView复用 或者用collectionView做无线轮播
3、使用CF开头的东西一定要记得释放
4、切图:背景只需要切一小条就行 1K 2K 启动图片一般是10K 20K
5、profile -> leaks 检查内存泄露
UItableView循环利用(原因,流程) 数据持久化(具体用哪一种) 手势 UIView动画
在tableView中第一次显示cell时,会创建新的cell(cell会对应一个标识)并且只显示当前tableView展现出来的数量,当cell从tableView中消失时,会被放入到tableView的缓存池当中,下一个cell出现时不会重新创建新的cell ,而是先从缓存池中拿出对应标识的cell使用,但是缓存池的cell包含着上一次的图片,而我现在要显示的cell并没有图片,所以会出现利用有图片的cell,所有布局混乱
而想要解决这个问题,1、都有label,都要显示文字:就是当cell出现时使用数据给其赋值(覆盖掉原有的数据),将数据和cell绑定,这样可以覆盖缓存池中cell的数据,当然也可以在其显示以前将其数据清空 2、要显示的cell没有图片,而缓存池中的cell有图片:在setTopic里判断要显示的cell是否有图片,如果有就把传给cell的topic模型里的图片数据赋值给图片控件,如果没有图片,将图片控件hidden
数据持久化
常用的数据持久化方式有:
属性列表(plist文件)
归档(存储自定义的类的对象时;存储用户的数据(昵称,uid))
偏好设置(NSUserDefault(存储一些简单的数据(用户的设置)))
sqlite3、core data、FMDB(大量数据的时候)
createtable student IF NOT EXISTS (id integer, name text, age text)
当有少量基础数据类型的数据和NSArray、NSDictionary需要储存并且无需加密时,就以使用plist文件
储存少量的数据,而且需要加密,比如登陆密码、获取的accessToken时,或者需要储存对象,比如做收藏夹、最近访问,都可以使用键值归档
偏好设置的话就是储存一些用户设置信息,比如程序中设置当中的一些开关的Bool值等版本号等等
当需要储存大量的数据时,比如需要离线缓存一些数据,就需要使用数据库了,sqlit3是c语言的东西,使用起来不是特别方便,而FMDB是封装的sqlite3使用起来比较方便,所以一般开发当中都是使用FMDB
UIView动画 是对Coreanimation的封装
Core animation:
组动画:执行一组动画
属性动画:基础动画 关键帧动画
转场动画:可以自定义
使用:
1.创建动画对象 CAKeyFrameAnimation * anim = [alloc] init];
2.设置属性 keyPath = @“layer 的属性” 并且支持KVC
3.添加到layer上自动执行。
注意:1、coreanimation动画并不会真正改变frame 只是作用有layer
2、core animation动画执行完会自动回复到原来的位置,如果不想让其恢复,fullModel complateXXX
GCD NSOperationQueue(底层、常用的函数,什么时候用)
在开发过程当中使用的多线程方式一般有三种,NSThread,NSOperation/NSOperationQueue,GCD
NSThread需要手动管理线程的生命周期,使用NSThread可以中途取消任务,也可以设置线程的优先级(0-1 越大优先级越高,默认都是0.5)在NSObject中苹果官方对其进行了封装
可以直接调用
-(void)performSelectorInBackGround:(SEL)aSelectorwithObject:(id)arg;
在后台直接调用一个方法执行,本质就是自动建一个线程,然后在其中执行一个操作
-(void)performSelector:(SEL)aSelectoronThread:(NSThread*)the withObject:(id)arg waitUntilDone:(BOOL)wait
在指定线程上执行一个操作,需要用户创建一个线程对象
-(void)performSelectorOnMainThread:(SEL)aSelectorwithObject:(id)arg waitUntilDone:(BOOL)wait;
在主线程执行一个操作
-(void)performSelector:(SEL)aSelectorwithObject:(id)arg afterDelay:(NSTimeInterval)time;
另开一个线程延迟指定时间后再执行这个操作
NSOperationQueue 是一个线程队列 可以创建一个NSOperation对象来放入队列中执行,一般是使用NSOperation的子类来创建一个任务,NSOperation有两个子类,一个是NSInvocationOperation 另一个是NSBlockOperation,使用NSOperationQueue可以设置最大线程并发数量,并且可以使用[operation1addDependency:operation2】来_添加依赖,operation1需要等到operation2执行完毕后再执行
GCD
GCD是一种基于C语言的一种多线程开发机制,
在GCD当中有两种队列 串行队列:在当前线程执行,添加在其中的任务按照顺序依次执行
并发队列:将添加进来的任务分配在可用的处理器上,同时执行。
在GCD中也有两种执行方法,dispatch_async 异步执行
dispatch_sync 同步执行
可以通过dispatch_queue_t queue = dispatch_queue_creat(“你的队列名”,DISPATCH_QUEUE_SERIAL)
来创建一个串行队列
通过dispach_get_main_queue() 获得主队列 一般在主队列中执行更新UI的方法
而获取并发队列的方法类似 dispatch_queue_creat)(“你的队列名”,DISPATCH_QUEUE_CONCURRENT)
但是一般在开发中我们无需创建一个新的并发队列,我们可以通过
dispatch_get_global_queue 来获取一个全局并行队列:
下面说一下GCD当中常用的方法
dispatch_apply():重复执行某个任务,不过这个方法没有办法异步执行(不过可以用dispatch_async包装一下就OK了)
dispatch_once() 这个方法只会执行一次,从此以后在程序没有退出以前就不会在执行,一般用来自定义一个单例对象是使用
dispatch_after()可以延迟一定时间执行一个任务,并且是异步的。
虽然多线程能够提高程序的性能,但是有时候当多个线程抢夺同一个资源是就需要使用线程同步了 NSThread使用线程同步一般可以使用NSLock同步锁,还有NSCondition, 但是一般使用@synchronized(self){ }代码块,这样比较方便
@synchronized(self){
// 修改
}
{
NSlock l = [NSLockalloc]init];
[l lock];
// 修改操作
[l unlock];
}
网络编程:AFN 和 ASI
AFN和ASI都是网络请求数据的框架 但是它们两个有很大的区别
1.AFN直接操作的对象是AFHTTPClient 它是一个实现了NSCoping协议的NSObject子类,AFHTTPClient是一个封装了一系列操作方法的工具类,处理请求的操作类是一系列单独的,基于NSOperation封装的,AFURLConnectionOperation的子类
ASI的直接操作对象是ASIHTTPRequest,是一个实现了NSCoping协议的NSOperation子类initialize和initwithURL:方法中初始化相关属性并配置一系列请求相关参数默认值,此外ASIHTTPRequest还提供了一系列方法用来配置请求对象
2.AFN对JSON,XML,Plist,Image四种数据进行了处理,开发者可以直接得到想要的数据类型
ASI没有针对数据做任何处理,只是预留了接口共开发者使用
3.AFN是基于NSURL框架,并且只提供异步调用方法,回调时使用block
ASI是基于CFNetwork框架,提供了同步异步两种方法,回调是可以使用代理,也可以使用block
4,ASI的底层是CFNetwork,而AFN的底层NSURL也是基于CFNetwork开发的,所以ASI比AFN更加底层
5,当项目网络逻辑不是特别复杂的时候可以使用AFN更加方便,当项目比较大,网络定制型要求高时,就可以考虑使用ASI
SDWebImage的底层
SDWebImage是使用NSOperation/NSOperationQueue进行异步加载图片,当它加载图片后会在程序沙盒下的缓存目录中创建一个文件夹,将下载的图片资源储存在文件夹当中,图片名就是图片的下载路径,当下次再次需要加载图片时,它会先在缓存文件夹中根据路径名进行查找如果找到就直接使用,如果没有再从网络上下载
项目:
自适应Cell(流程)
1、自定义Cell
2、最好对控件进行分层设计,这样的设计方式可以增加代码的复用性,看起来也比较清晰,更改需求时,代码的变动也比较小
3、计算每个控件的frame,创建frame模型 ,里面计算每个控件的frame
4、通过VC拿到frameModel 1、返回每个cell的行高 2 把frame模型传给cell,给对应的控件frame赋值
程序构架
1、观察分析原型图
2、设计架构:是tabBarVC包含 多个navigationVC还是其他的情况
3、多控制器切换的话:如果4、5个VC,不需要考虑VC复用,如果20多个VC,考虑控制器的复用:1、3个tableView的循环利用 2、collectionView的cell中放tableView
1、写框架前 要仔细分析各个模块及控制器之间的跳转和依赖的关系,比如分析一下看看这几个控制之间有没有什么样的view是可以重用的,如果有的话,可以自定义一个view,以备以后重用时简单
自定义控件(流程)
自定义控件经常使用,一般情况下,自定义一个控件首先你要知道这个控件是干嘛用得,它需不需要显示图片,文字,需不需要点击,需不需要变动frame等,然后根据相应的需求留下对应的接口,比如点击一个自定义控件,那这个控件需要通知控制它被点击了,简单情况下如果只有一个button,只需要通知一个控制器,就可以通过外部定义一个 add_Target方法连接内部的button的addTarget方法
如果view处理的逻辑比较复杂需要使用代理协议来传递更多的信息,参数,如果一处点击需要通知多个控制器进行响应,就需要用到KVO,保证自定义控件与其他控件或控制器之间尽量没有任何关系,调用时就是通过控件在.h中留下的方法(接口)进行操作的,降低耦合性。
适配:
适配原来使用的是autoResizeing,现在在storyboard和xib中一般是使用autolayout
适配时使用的第三方有 masonry
基于iOS SDK 的布局分类 UIView+AutoLayout
高寿东:SDAutoLayout
masonry的代码十分简洁,使用链式语法,使用起来也十分方便,下面说一下主要用法,比如布局一个view让它在显示居中,宽高都是100
[viewmas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
这样就完成了一个居中view的布局,这里面可用的属性有top,bottom,left,right,width,height,leading,trailing,centerX,centerY,baseline其实还可以直接使用center,edges内边距
masonry一共有3种布局方法
mas_makeConstraints:创建一个新的约束,在autoLayout中对同一个对象设置多个重复约束会报错
mas_updateConstraints:更新在block中出现的约束,不会出现重复的约束
mas_remakeConstraints:清除之前的所有约束,仅保留block中的新的约束
设置约束的方法也是三种
mas_equalTo()等于
mas_greaterThanOrEqualTo()
大于等于mas_lessThanOrEqualTo() 小于等于
UIView+AutoLayout的使用
更接近autoLayout的底层,有三种设置方式,
第一种以autoSetDimension开头的,约束size类(就是设置宽高)
第二种以autoPin开头,约束位置的(就是设置距离上下左右的距离)
第三种以autoAlign开头,约束对齐(就是设置XY轴对齐的)
语法简单一看就知道了
百度地图,及友盟分享
百度地图:
百度地图的集成过程并不复杂,以下是集成时需要注意的几点
1.在官网注册应用,获取appkey.
2.下载SDK并导入项目中。
3.添加必要的框架。
4.注册appkey。
遇到的问题:
0.百度地图的静态库使用c++编写的,所以项目中至少有一个.mm文件,不然会报错。
1.在appDelegate中启动百度地图引擎时,设置代理,在回调方法中提示错误参数230(如果正确的话是0) 解决办法:这个时候你需要注意你的info.plist文件中的Bundle identifier 还有工程里面的Bundle identifier 应该和你申请appkey 的时候填写的sdk 安全码不一致
2.提示引擎启动失败,这个一般是因为你拉入忘记拉入mapapi.bundle了
因为以后迅雷就不再更新.a 静态库了,所以在此使用的是BaiduMapAPI.framework,但是上述问题是两种类型都会遇到的问题
收藏、最近
收藏和最近主要就是封装一个业务类对数据进行增加和删除,保存数据时要重写数据的equalto方法(因为计算机是根据内存地址比较的,而有时候内存地址虽然不同,但是储存的数据确实一样的,所以一般根据数据的位置标识(例如id值)比较)
如果是做最近,就需要将上一次的数据删除,添加新的数据进来,如果在收藏时需要记录控件的编辑和选中状态,就需要在数据模型中添加相应的属性,利用数据来控制控件的状态
常出现的问题就是使用tableview时会出现循环利用的问题,这个问题就可以使用数据的值来避免,每次加载cell时,他的状态是受数据控制的,数据不会发生循环利用的问题,这个问题也就不会出现了
FMDB
使用FMDB的流程
1创建一个库
2建一个表(表里面要定义你要储存的数据类型,就是字段())——》
3然后就是插入数据,修改,删除,查询数据
创表语句:create table if not exists t_student (id ingtger autoincrement primary key, name text, age integer)
增删改查必须记住
推送流程
本地推送一般可以用来提示长时间未进入应用的用户,也可以用来做闹铃。
(一个程序可以推送,首先你要配置推送证书)
下面详细说一下远程推送的流程:
1.当你的程序需要推送时,通过UIApplication中的registerUserNotification注册远程推送,注册后,你的程序会通过iOS系统向APNs服务器请求,APNs服务器接到请求后会将请求设备的device token(设备令牌)发送回你的应用,在UIApplication的代理方法中可以接收到device token,如果请求失败也会通过代理方法返回错误信息
2.当应用程序拿到device token后,就可以将device token传给应用提供商服务器,服务器就知道了这台设备可以推送消息了,然后将device token储存在服务器内部,device token的生成算法只有苹果公司才知道,所以为了防止苹果修改算法造成推送失败,最好每次启动程序时都请求一次device token,在device token发生改变时,告诉服务器新的device token
(推送一般情况下是程序提供商向用户推送一些最新的消息或者资讯,不过比如QQ,微信等可以在离线的情况下进行消息的提醒,下面以qq推送离线消息为例,相比从服务器推送,qq离线消息的推送是由客户端编辑信息的)
3.现在如果程序要推送消息了,就可以将消息和要发送的对象的账号发送给程序提供商服务器,服务器会通过你要推送的对象的账号信息找到对应绑定的device token,然后将推送消息内容和device token传给APNs服务器
4.APNs服务器在接收到消息内容和device token后会查找已注册的设备然后将对应的信息和device token推送到指定的设备上,设备通过device token中的app id找到要推送的app,然后信息会按照app的推送设置显示信息
二维码
做二维码的话,可以使用的第三发库有ZBar和ZXing 具体使用方法可以去网上查看文档
但是现在iOS中的AVFoundation框架中也集成了二维码扫描,用起来也十分方便,并且扫描速度也更快,性能更好,还可以使用AVFoundation框架生成二维码