美文网首页
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