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文件
储存少量的数据,并且须要加密,比方登录password、获取的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 还有project里面的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系统向APNsserver请求,APNsserver接到请求后会将请求设备的device token(设备令牌)发送回你的应用,在UIApplication的代理方法中能够接收到device token,假设请求失败也会通过代理方法返回错误信息
2.当应用程序拿到device token后。就能够将device token传给应用提供商server。server就知道了这台设备能够推送消息了。然后将device token储存在server内部,device token的生成算法仅仅有苹果公司才知道,所以为了防止苹果改动算法造成推送失败,最好每次启动程序时都请求一次device token。在device token发生改变时。告诉server新的device token
(推送普通情况下是程序提供商向用户推送一些最新的消息或者资讯,只是比方QQ,微信等能够在离线的情况下进行消息的提醒,以下以qq推送离线消息为例。相比从server推送,qq离线消息的推送是由client编辑信息的)
3.如今假设程序要推送消息了,就能够将消息和要发送的对象的账号发送给程序提供商server,server会通过你要推送的对象的账号信息找到相应绑定的device token,然后将推送消息内容和device token传给APNsserver
4.APNsserver在接收到消息内容和device token后会查找已注冊的设备然后将相应的信息和device token推送到指定的设备上,设备通过device token中的app id找到要推送的app。然后信息会依照app的推送设置显示信息
二维码
做二维码的话,能够使用的第三发库有ZBar和ZXing 详细用法能够去网上查看文档
可是如今iOS中的AVFoundation框架中也集成了二维码扫描。用起来也十分方便,而且扫描速度也更快,性能更好。还能够使用AVFoundation框架生成二维码