美文网首页
iOS 知识小册子 第二期

iOS 知识小册子 第二期

作者: Joe的技术博客 | 来源:发表于2015-10-07 21:48 被阅读128次

这期主要回顾一些 UI 的知识点

1. loadView, viewDidLoad 和 viewDidUnload

loadView 主要是用来创建 controller 的 View, 并且创建过程是懒加载的, 也就是只有用到 controller 的 view 的时候, 才会创建该 controller 的 view

viewDidLoad 主要是对界面做一些初始化操作, 方法调用在 loadView 之后

viewDidUnload 主要是在发生内存警告且 view 被释放的时候会调用, 所以一般用在释放跟界面相关的资源, 将相关的实例都赋值为 nil; 与 dealloc 不同的是 该方法只会在 view 被释放的时候调用, dealloc 是在 UIViewController 被释放时调用

2.  UINavigationController, UITabBarController 和 UICollectionView

UINavigationController 的使用步骤

2.1. 创建 UINavigationController

2.2 设置导航控制器为 window 的 rootViewController

2.3 添加子 UIViewController 到导航控制器

UINavigationController 常用的属性和方法

2.4 push 相关如: pushViewController:

2.5 pop 相关如: popViewControllerAnimated:

2.6 初始化相关 initWithRootViewController: 如果用自定义 UINavigationBar 初始化 导航控制器用 initWithNavigationBarClass:

2.7 

2.6 viewControllers 和 childViewControllers(readOnly)

topViewController

navigationBar

UINavigationController 是通过栈的形式来管理子控制器, 导航条(navigationBar)的内容和栈顶控制器有关(navigationItem)除了返回按钮是由上一个 UIViewController 决定的

UINavigationBar : iOS 7 以前是不透明的, iOS 7 以后是透明的

在透明情况下, 与 contentView 会重合一部分区域

在不透明情况下, contentView 是跟在导航条的下面

横屏默认高度是 32, 竖屏默认高度是 44

在UINavigationController设置UINavigationController的导航条,

UINavigationBar* navigationBarAppearance = [UINavigationBar appearance];

[navigationBarAppearance setTintColor:[UIColor redColor]];

通过appearance对象可以设置导航条的属性

在UINavigationController可以设置UIBarButtonItem的属性

[UIBarButtonItem appearance];

导航条的返回按钮是交给UINavigationBar管理的


UIStoryboardSegue(手动类型, 自动类型)

identifier

sourceViewController

destinationViewController

手动类型的 segue 需要 手动执行 performSegueWithIdentifier: 可以在需要在UIViewController的prepareForSegue: 里面拦截执行segue消息

控制器之间传递数据: 顺传(prepareForSegue:), 逆传(delegate)


UITabBarController 常见属性和方法

1. selectedViewController

2. selectedIndex

3. tabBar(readOnly, 可通过KVC进行修改)

4. delegate

5. viewControllers



UICollectionView可以从缓冲池中取Cell, 取不到系统会帮我们创建, 需要告诉系统我们需要创建什么样的Cell, 注册Cell到系统中

[collectionView

registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@""];

如果cell是从xib中创建的需要注册xib


UICollectionViewLayout (父类)

UICollectionViewFlowLayout(流水布局)




3. UITextField 监听事件的几种方法

addTarget:

delegate

NotificationCenter

4. UITableViewCell 的 initWithStyle: 和 awakeFromNib: 

5. Preference 和 NSKeyedArchiver

[[NSUserDefaults standardUserDefaults] setObject:@""forKey:@""]

[[NSUserDefaults standardUserDefaults] synchronize]

偏好设置的局限: 将所有的数据只保存到一个文件, 一般保存应用程序配置信息;不能存储自定义的对象

[NSKeyedArchiver archiveRootObject:@""toFile:@""]  对应 [NSKeyedUnarchiver unarchiveObjectWithFile:@""]

自定义的对象用归档必须实现NSCoding协议

保存文件: - (void)encodeWithCoder:(NSCoder*)aCoder

读取文件: - (instancetype)initWithCoder:(NSCoder*)aDecoder

6. 应用程序沙盒文件系统目录 (iOS 8 以前每个应用程序沙盒隔离,  iOS 8 以后开放)

Documents : 需要持久化的重要的数据, iTunes 同步设备会备份该目录

Library/Caches: 需要持久化非重要的很大数据, 同步设备不会备份

Library/Preference: 同步设备会备份, 一般存储系统的偏好设置

temp: 临时数据

获取程序沙盒下的 Documents 目录:

[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]

获取应用程序沙盒目录: NSHomeDirectory()

7. UITableView 编辑模式

要重写UITableViewDataSource的commitEditingStyle:方法会有删除界面, 在这个方法里面判断是删除还是添加

只有在 UITableView 编辑模式下才能看见cell的添加按钮, editing设置true开启编辑模式

告诉系统开启的是什么编辑模式: editingStyleForRowAtIndexPath:

先delete模型数据, 再删除tableview指定的cell(性能优于reloadData)

8. Modal

presentViewController:

dismissViewControllerAnimated:(可以调用该控制器以及该控制器自控制器让该控制器消失)

9. Quartz2D

只有在drawRect: 方法才能取得跟view相关的图像上下文

当view第一次显示在屏幕上的时候会调用drawRect:方法

调用view的setNeedsDisplay 或者setNeedsDisplayRect时系统会调用drawRect:


获取Layer的上下文: CGContextRef contextRef =UIGraphicsGetCurrentContext();

设置起点: CGContextMoveToPoint(contextRef,10,0);

设置终点: CGContextMoveToPoint(contextRef,20,20);


设置绘图状态: CGContextSetRGBStrokeColor(contextRef,1.0,0,0,1.0);

设置线条宽度: CGContextSetLineWidth(contextRef,10);

设置线条起点和终点样式: CGContextSetLineCap(contextRef,kCGLineCapRound);

设置线条转角的样式: CGContextSetLineJoin(contextRef,kCGLineJoinRound);


渲染图形到view上: CGContextStrokePath(contextRef); (实心CGContextFillPath(contextRef));

补充: 

绘制线条只能通过空心来画 (CGContextStrokePath)

关闭图形 CGContextClosePath(contextRef);

绘制四边形 CGContextAddRect(contextRef,CGRectMake(10,10,100,100));

矩阵操作(先设置再绘图) CGContextRotateCTM(contextRef,M_PI_4);

绘制圆 CGContextAddEllipseInRect(contextRef,CGRectMake(100,100,30,40));

超出圆的部分裁剪 CGContextClip(contextRef); 渲染圆之前调用

绘制圆弧 CGContextAddArc(contextRef,30,30,30,0,M_PI_2,0);

调用OC的方法设置绘图颜色: [[UIColor redColor] set]; 此方法不能用早CALayer的drawInContext:中


贝塞尔曲线 

当前点: CGContextMoveToPoint(contextRef,10,10);

控制点和终点: CGContextAddQuadCurveToPoint(contextRef,30,30,20,20);


图形上下文栈

保存上下文 CGContextSaveGState(contextRef);

还原上下文 CGContextRestoreGState(contextRef);


凡是通过Quartz2D中的带有create/copy/retain 方法创建出来的值都必须手动的释放

CGPathRelease(path) / CFRelease(path)


截屏

创建一个bitmap的上下文

UIGraphicsBeginImageContext(self.viewForFirstBaselineLayout.frame.size);

将屏幕绘制到上下文 

[self.layer renderInContext:UIGraphicsGetCurrentContext()];

从上下文中取出图片

UIImage*drawImage =UIGraphicsGetImageFromCurrentImageContext();

NSData*data =UIImagePNGRepresentation(drawImage);


保存到相册

UIImageWriteToSavedPhotosAlbum(drawImage,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);

10. 手势识别器(UIGestureRecognizer, 抽象类)


通过touches方法监听view事件, 有下面几个局限

1. 需要自定义view(UIStoryboard 可以拖手势识别控件)

2. 由于view内部的touches方法中监听的触摸事件, 以此默认情况下, 无法让其他的外界对象监听view的触摸事件

3. 不容易区分用户的手势行为


UITapGestureRecognizer 点击

UIPinchGestureRecognizer 捏合

UIPanGestureRecognizer 拖拽

UISwipeGestureRecognizer 轻扫 (默认从左往右)

UIRotationGestureRecognizer 旋转

UILongPressGestureRecognizer 长按


1. 创建手势识别器 

UITapGestureRecognizer*tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];

tapGestureRecognizer.delegate = self

2. 添加手势识别器到view

[self.view addGestureRecognizer:tapGestureRecognizer]

3. 监听手势识别器

[tapGestureRecognizer addTarget:self action:@selector(tapTest)];

注: UIImageView 默认是不支持和用户交互的

11. CALayer 和 UIView

在创建UIView 的时候, UIView内部会自动创建一个CALayer, 用过UIView的layer属性可以访问这个图层

UIView之所以显示在屏幕上, 完全是因为它内部的一个图层

UIView不具备显示的功能, UIView 的CALayer才具有显示的功能

通过操作CALayer对象, 可以很方便访问UIView的一些外观属性,比如

阴影, 圆角大小, 边框宽度和颜色

如果一个控件是另外一个控件的子空间, 那么这个控件的layer也是另外一个控件layer的子layer

CALayer是定义在QuartzCore框架中的 (跨平台)

CGImageRef 和 CGColorRef是定义在CoreGraphics中的 (跨平台)

相比CALyer(性能高于UIView), UIView 多了事件处理的功能


CALayer常见属性

self.layer.borderColor= [UIColor redColor].CGColor;

self.layer.cornerRadius=10; (设置主图层的圆角)

self.layer.masksToBounds=YES; (类似UIView的self.clipsToBounds=YES)

self.layer.shadowColor= [UIColor redColor].CGColor;

self.layer.shadowOffset=CGSizeMake(10,30);

self.layer.shadowOpacity=0.5;(默认是完全透明的0)

self.layer.contents= (id)([UIImage imageNamed:@""].CGImage); (设置的image展示在子图层)

transform, bounds, position

[self.layer setValue:@(10)forKey:@"transform.translation.x"];

自定义CALyer

CALayer*layer = [CALayer layer];

[self.layer addSublayer:layer];


Position  和 AnchorPoint

Position 用来设置 CALayer 在父层中的位置, 以父层的左上角为原点(0, 0)

AnchorPoint 决定CALayer的哪个点在position属性所指的位置, 以自己的左上角为原点, x,y取值范围都是0-1, 默认是(0.5, 0.5)

所有非Root Layer(手动创建CALyer), 都有隐身动画(动画属性)

关闭隐身动画

[CATransaction begin];

[CATransaction setDisableActions:YES];

[CATransaction commit];


CALayer 画图的两种方式(都需要手动调用CALayer 的 setNeedsDisplay)

1. CALayer 的 drawInContext: 

2. CALayer的delegate

- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx

10. Core Animation

Core Animation 是自己接作用在 CALayer 上的, 并非UIView, 执行动画的过程都是在后台操作的, 不会阻塞主线程


1. 初始化一个CAAnimation(抽象类)的子类对象, 并设置一些相关属性

2. 调用CALayer 的 addAnimation:forKey: 方法增加CAAnimation对象到CALayer中

3. 调用CALayer 的 removeAnimationForKey:可以停止CALayer中的动画


CAAnimation 的四个子类

CABasicAnimation (fromValue, toValue)

CAKeyFrameAnimation (values, path, keyTimes)

CATransition (type, subtype, startProgress, endProgress)

CAAnimationGroup (animations)

局限: 表面动画执行, 实际上控件的frame没有改变, 如果需要frame也改变, 用UIView的动画

参照: http://www.jianshu.com/p/8c1c1697c0ce

11. initWithFrame: 和 layoutSubviews:

initWithFrame一般用在自定义控件中,对自定义的控件添加子控件, 保证封装性

在自定义的控件中一般都需要delegate属性与外交交互

设置控件的frame必须要在layoutSubviews: 这个方法中操作, 如果在initWithFrame:设置frame, 在init方法中调initWithFrame, frame是没有值的

12.  获取系统的iOS版本

[[UIDevice currentDevice].systemVersion doubleValue]

13. UIImage图片拉伸和切割

1. resizableImageWithCapInsets:

2. stretchableImageWithLeftCapWidth:

iOS 7 以后可以用图形化界面设置图片拉伸, 拉伸参数编译器会为你设置


图片切割

CGImageCreateWithImageInRect(image.CGImage,CGRectMake(0,0,20,20));

注意: CGImage中rect是当像素来使用, UIKit是点坐标系, 在非retain屏中一个点等于一个像素, retain屏等于两个像素

可以通过[UIScreen mainScreen].scale 来获取是否为retain屏

14. + (void)initialize 和 + (void)load

该类第一次使用才会调用initialize, 在父子关系中可能会调用多次

load

15. 多线程 

iOS中的主线程(UI线程)

显示(刷新)UI界面

处理UI事件

耗时的操作不要放在主线程

NSThread (程序员管理内存)

GCD (替代NSThread, 充分利用设备多线程, 自动管理内存)

NSOperation (基于GCD, 更加面向对象, 自动管理内存)

自定义NSOperation把想做的操作放在- (void)main中去执行, 还需要经常调用isCancelled方法对取消做出响应

注意: 自己创建自动释放池(因为异步操作无法访问主线程的自动释放池)

NSThread*thread = [[NSThread alloc]initWithTarget:self selector:@selector(run)object:nil];

[threadstart];

创建显示线程自动启动:

[NSThread detachNewThreadSelector:@selector(run)toTarget:self withObject:nil];

创建隐式并自动启动:

[self performSelectorInBackground:@selector(run)withObject:nil]

加锁 (锁一份代码只需要一分锁, 多把锁无效)可达到线程同步

@synchronized(self) {

}

线程之间通信:

转换线程的时候传数据 (常用情况是子线程下载完东西把数据传到主线程)

GCD两个核心概念

1. 任务 (同步还是异步)

2. 队列 (只影响任务的执行方式, 并发还是串行)

并发队列: 可以让多个任务并发(同时)执行,自动开启多个线程同时执行任务, 并发功能只有在异步(dispatch_async)函数下才有效 

获得全局的并发队列: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

串行队列: 一个任务执行完了再执行下一个

dispatch_queue_create("quequeName",NULL) 非ARC需要释放dispatch_release(queue);

也可以用CFRelease(queue), CoreFundation 和 Fundation框架的数据类型是可以相互转化的(桥接)

dispatch_get_main_queue() (线程间通信有用)添加到主线程的任务都会放到主线程中去执行

同步任务放到主线程可能会引起死锁

使用GCD步骤

1. 定制任务(同步, 异步具备开新线程的能力)

2. 将任务添加队列

GCD自动从队列中取出任务, 放到相应的线程中执行

同步: 在当前线程执行, 不具备开新线程的能力

异步: 在新的线程中执行任务, 具备开新线程的能力

并发: 多个任务同时执行

串行: 一个任务执行完后再执行另一个任务

常见的延迟操作: 

[self performSelector:@selector(delayTest:)withObject:nil afterDelay:3.0];

这个方法在当前程操作, 不会另开线程

dispatch_after 代码块, 只要不是主队列, 就会开线程执行

一次性代码: dispatch_once

16. 需要设置按钮的image 和 backgroundImage, 建议先把按钮的类型改为custom, 才能保证设置成功

17. 在OC中成员变量不能以new开头

18. 只有在init开头的构造方法方法中, 才能允许对self进行赋值, 默认的是驼峰命名


iOS 中发送HTTP请求的方案

1. 苹果原生

NSURLConnection

NSURLSession (iOS 7 )

常用类

NSURL: 请求地址

NSURLRequest

NSURLConnection 使用步骤

1. 创建一个NSURL对象, 设置请求路径

2. 传入NSURL创建一个NSURLRequest对象, 设置请求头请求体

3. 使用NSURLConnection发送NSURLRequest

19. JSON 和 XML

苹果原生: NSJSONSerialization(系列化器)常见方法

JSON - > OC对象

+ (id)JSONObjectWithData:

OC 对象 ->JSON

+(NSData *)dataWith

XML 解析:

1. 苹果原生

NSXMLParser: SAX方式解析, 使用简单 (比较适合大的文件)

GDataXML: DOM方式解析 (一次性将整个XML文档加载进内存, 比较适合小的文件解析, 需要添加libxml2.dylib库)

动态库需要在Build settings中

1. 搜索Header Search Paths添加/user/include/linxml2

2. 还需需要搜索Other Links, 结果Other Linker Flags中加-lxml2

3. 在ARC中导入第三方库(非ARC), 在Build Phases中Compile Sources的问价添加-fno-objc-arc

GDataXML使用:

1. GDataXMLDocument

2. GDataXMLElement

解析XML数据

GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData: data options: 0 error: nil];

获得文档里面的根元素: rootElement *root = doc.rootElement ;

获得跟元素里面所有的test元素:

NSArray *array = [root elementsForName:@"test"];

array 里面每个元素都是GDataXMLElement

GDataXMLElement *element = array[0] ;

[element attributeForName:@"node"].stringValue;

libxml2: 同时支持DOM 和 SAX


NSXMLParser*parser = [[NSXMLParser alloc] init];

parser.delegate=self;

[parser parse]; 同步执行

刷新表格


NSHTTPURLResponse 是 NSURLResponse 的子类, 用NSURLConnection(默认是get请求)发送异步请求放回的NSURLResponse, 只有转换成NSHTTPURLResponse, 才能拿到响应头,响应行等信息

发送post请求:NSMutableURLRequest

URL中不能包含中文, 得给中文进行转码

stringByAddingPercentEncodingWithAllowedCharacters: 

stringByAddingPercentEscapesUsingEncoding deprecated(苹果废弃的方法)

发送JSON给服务器仅仅设置请求体是不够的, 得在请求头里面设置MIMEType

[request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];

默认情况Content-type是普通参数

网络状态监控:

需要添加SystemConfiguration.framework框架

导入Reachability.h / Reachability.m

Reachability *reachability = [Reachability reachabilityForLocalWiFi];

主动获得wiFi状态:

NetworkStatus status = reachability.currentReachabilityStatus;

需要调用reachability(全局)对象的开始监听方法才能监控网络变化通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkServiceTypeChange:)  name:kReachbilityChangeNotification object:nil];


小文件下载:

NSData

NSURLConnection send.....

大文件下载:

创建完对象后会发起一个异步的请求

NSURLConnection connection....delegate(NSURLConnectionDataDelegate)

无暂停功能,只能取消

要做断点下载需要设置请求头:

NSString*range = [NSString stringWithFormat:@"bytes=%lld-", currentLength];

[request setValue:range forHTTPHeaderField:@"Range"];

多线程断点下载:



利用NSFileManager 和 NSFileHandle 优化大文件下载内存: 

NSFileManager创建一个0kb的文件(Caches)

NSFileHandle 把句柄移到创建文件的最后面

NSFileHandle 写数据到文件 (用完需要关闭文件并且把它清空)


NSURLSession: iOS 7 推出, 目的是取代NSURLConnection

得到Session对象:

NSURLSession*session = [NSURLSession sharedSession];

任务: 任何请求都是一个任务

NSURLSessionDataTask: 普通的GET / POST 请求

NSURLSessionDownloadTask: 文件下载 (系统默认是下载到temp文件夹下, 需要用NSFileManager把下载文件剪切到Documents文件夹下)

如果要想知道下载任务进度,session需要用NSURLSession得sessionWithConfiguration:方法

创建,在此方法中设置delegate(注意session创建的任务方法里面不能有block, 否则delegate里面的方法不会调用)

NSURLSessionUploadTask: 上传任务, 一般HTTP服务器不支持


NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request ...

[dataTask resume];

dataTask cancelByProducingResumeData: 做断点下载需要保存传入的data方便下次继续下载downloadTaskWithResumeData:


KVO、通知NSNotification和代理的比较

KVO/通知NSNotification/代理这三种方法主要是用来监听事件发生的

两者都是观察者模式,不同的是,KVO是被观察者直接发送消息给观察者,是对象间的交互,而通知则是观察者和被观察者通过通知中心对象之间进行交互,即消息由被观察者发送到通知中心对象,再由中心对象发给观察者,两者之间并不进行直接的交互

代理只能一对一,一个对象只有一个代理,而KVO和通知可以一对多,一个通知可以发给多个观察者


  

相关文章

网友评论

      本文标题:iOS 知识小册子 第二期

      本文链接:https://www.haomeiwen.com/subject/oucncttx.html