美文网首页
iOS官方文档阅读记录

iOS官方文档阅读记录

作者: xymspace | 来源:发表于2018-06-29 19:44 被阅读28次
  • 经过筛选文档内容和下午3小时的学习,认为如下方案具有可行性,计划从Objective-C开始学习.学习计划以库名作为大纲.

从7.1日开始

重点学习 :

  • Objective-C(10个子目录)

---- 16天 --- 结束时间 : 7.17

(runtime非常核心.围绕runtime,系统方法加载顺序,编程中常见方法3个点,串联本章相关知识,最后2天时间梳理)

  1. NSObject

    • 系统自主调用的方法 (可重写,重写super调用方法实现父类调用):

      initialize
      load
      dealloc
      description

    • 常用方法 :

    • copymutableCopy
         可变对象发送此消息 : copy 与 mutableCopy 都可生成新对象.
         copy生成的是不可变对象, mutableCopy生成可变对象.
         生成的只是一个新的容器,容器内容未开辟新的空间.
    
深拷贝与浅拷贝.png
  > - `isKindOfClass` 与`isSubclassOfClass`
        
        用于判断当前类的所属,方便下一步编程使用
  • runtime :

(KVC与KVO!

是runtime的具体应用)
>- 是oc的底层,基本通过 C 和汇编写 ,使c语言扩展出面向对象的功能.编译器会将 OC 代码转换成运行时代码,在运行时确定数据结构和函数.

  • 方法的调用本质 : 对象发送消息.

与runtime 匹配的消息机制 :


// performSelector最多携带2个参数
performSelector : withObject : afterDelay :
performSelector : withObject : afterDelay : inModes :
performSelectorOnMainThread :  withObject : waitUntilDone :
performSelectorOnMainThread :  withObject : waitUntilDone : modes :
performSelector : OnThread :  withObject : waitUntilDone :
performSelector : OnThread :  withObject : waitUntilDone : modes :
forwoardingTargetForSelector :
resolveClassMethod :
doesNotRecognizeSelector :
classFallbacksForKeyedArchiver :
#import <objc/message.h> 
或者直接导入
#import <objc/runtime.h>

实际应用 :
1. 获取某各类中所有的方法
2. 获取某个类中所有的属性
3. method swizzling (黑魔法)
如果类别中对系统方法进行method swizzling(方法交换),使用category中的load方法。
文档中说明了initialize和load的区别:
load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么 initialize也不会被调用.

需要清楚的几个runtime相关概念 :

  1. Method
    代表类中某个方法的类型
  2. Ivar
    是表示成员变量的类型。
    3.IMP
    一个函数指针,由编译器生成.当你发起一个 ObjC 消息之后,最终它会执行的那段代码,就是由这个函数指针指定.IMP 这个函数指针指向该方法的实现.
  • runLoop :

RunLoop相关联类(CoreFoundation)

  • Core Foundation中关于RunLoop的5个类

    • uCFRunLoopRef

    • uCFRunLoopModeRef -- RunLoop 模式

    • uCFRunLoopSourceRef -- 各种事件(渲染、点击等等)

    • uCFRunLoopTimerRef -- 基本上就是NSTimer

    • uCFRunLoopObserverRef -- Observer

CFRunLoopRef

  • 各线程间RunLoop相互独立,不受影响

CFRunLoopModeRef

  • 一个 RunLoop 包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer

  • 每次RunLoop启动时,必须指定一种Mode,这个Mode称为CurrentMode

  • 如果要切换Mode,要先退出当前Loop,再重新选择一个Mode后进入

  • 这样做保证了各Mode下的 Source/Timer/Observer 相互独立,不受影响

  • 系统默认注册了5个Mode:

    • CFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

    • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

    • UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用(系统内部调用)

    • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到(系统内部调用)

    • CFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode(它可以同时表示多个Mode-->default、tracking)

CFRunLoopSourceRef

  • 事件源,分为:

    • 以前的分法:

      • Port-Based Sources

      • Custom Input Sources

      • Cocoa Perform Selector Sources

    • 现在的分法(基于栈):

      • Source0:非基于Port的

      • Source1:基于Port的

  • 在这里简单说明RunLoop工作原理的一部分:

  • 用户的点击、摇晃等等一系列事件由Source1接收,包装成Event对象,交给Source0处理

CFRunLoopTimerRef

 // 调用了scheduledTimer返回的定时器,已经自动被添加到当前runLoop中,而且是NSDefaultRunLoopMode
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

 // 修改模式
 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

uCFRunLoopObserverRef

  • 函数:
/**
* 顺序:
1、创建observer
2、添加观察者
3、释放observer
*/
 // 创建observer

//CFAllocatorGetDefault  默认值
//YES  表示重复监听

 CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

 NSLog(@"----RunLoop状态发生改变---%zd", activity);

 });

 // 添加观察者:监听RunLoop的状态

//CFRunLoopGetCurrent()  表示要监听的RunLoop -- 这里是当前RunLoop

 CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

 // 释放Observer
 CFRelease(observer);
  • 可监控的状态:
 kCFRunLoopEntry = (1UL << 0),// 即将进入Loop

 kCFRunLoopBeforeTimers = (1UL << 1),//即将处理Timer

 kCFRunLoopBeforeSources = (1UL << 2),//即将处理Source

 kCFRunLoopBeforeWaiting = (1UL << 5),//刚进入休眠

 kCFRunLoopAfterWaiting = (1UL << 6),//刚从休眠中唤醒

 kCFRunLoopExit = (1UL << 7),//即将退出Loop

 kCFRunLoopAllActivities //所有活动状态

RunLoop应用场景

  1. 开启一个常驻线程(让一个子线程不进入消亡状态,等待其它线程发来消息,处理其它事件)
  2. 在子线程开一一个定时器
  3. 在子线程中进行一些长期监控(沙河监控、连网监控等)
  4. 可以控制定时器在特定模式下执行
  5. 可以让某些事件(任务、行为)在特定模式下执行
  6. 可以添加Observer 监听RunLoop的状态。如监听点击事件的处理(在所有点击事件之前做一些事情)
  • 相关知识点 :

    • runLoop在即将进入loop时,会创建自动释放池,这个创建order(次序)优先级最高(是-2147483647),保证创建释放池发生在其它所有事件回调之前
    • 在RunLoop睡眠之前会释放旧的自动释放池,并创建新的自动释放池(kCFRunLoopBeforeWaiting)
      即将退出RunLoop时,会释放自动释放池,这个释放操作的order是排在所有操作的最后的,优先级最低(是-2147483647),保证创建释放池发生在其它所有事件回调之后
      ( kCFRunLoopBeforeWaiting)
      建议 : 在子线程中启动RunLoop,用自动释放池进行包装
      注:order 的数值越小,优先级越高
  • 苹果官方RunLoop介绍文档


https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html


  • 常用关键字

  • static
    • 作用1:添加了static关键字的全局变量,只能在当前类文件访问;反之则可以全局访问(使用extern关键字访问,访问同时可以修改其值)
    • 作用2:添加了static关键字的局部变量,会延长生命周期,为其开辟的内存会一直持有,直到程序结束才销毁;反之作用域结束,其持有内存销毁,再次访问,内存重新分配
作用1例:

//定义一个变量(未增加关键字static)

 int test = 1;

//因此,下面段引用代码,可以写在当前工程任意地方

 extern int text;

 text = 2;
作用2例:
int test = 1;

static int text = 1;
  • const
    const修饰的全局变量会变为全局常量,且只读(即不可更改的常量) ,但仍可全局访问
    例如:
/**const修饰谁,谁就不可变*/
const NSInteger age = 5;
/**
* oc语法下,外界访问的是name,所以const修饰name
*/
NSString *const name = @"Jim";

// 下面这句代码const修饰的是*name
// const NSString *name = @"Jim";
  • extern
引用关键字

引用全局变量:extern 类型名 变量名
引用全局常量:extern const 类型名 变量名
const + static 与 extern 可以组合使用,将const和static修饰的全局常量放在一个空的.m文件中,然后在头文件中使用extern关键字对这些全局常量进行引用,使用这些常量时,只需要导入头文件。建议将头文件引用的.m文件写相同名称,方便管理.

(其它不常用知识稍后再做汇总)

  • UIKit (28个子目录)

---- 30天 --- 结束时间 : 8.16
近来接触最为频繁的知识点 :

  • 父子控制器

同一个View在同一个父控件上添加n次,等于添加一次,因为这个View占有的内存一直是同一份

  • 如果2个控制器的View是父子关系(不管是直接还是间接的父子关系),那么这两个控制器也应是父子关系

    • 详解:一个控制器上添加了另一个控制器的View,当子控制器也需要监听一些事件(例如系统事件:屏幕旋转、屏幕摇动),就需要将子控制器与父控制器关联起来-->addChideViewController : ...。子控制器能够监听到事件的另一个前提:当前子控制器的View在父控制器上。为了方便管理,建议不进行跨级设置父控制器。也就是说,直接添加在上一级控制器上就好了
    • 移除:当View从父控制器上移除,要执行:[self.childViewController[index] removeFromSuperController]; 将View对应子控制器也移除
    • 导航跳转:(push/pop)当子控制器的父控制器不是导航控制器,而父控制器的上一层是导航控制器,正确设置控制器的父子关系,可以实现子控制器的导航跳转。
    • 模态视图:(present/dismiss)与导航是一个道理
    • didMoveToParentViewController:当在成为某一个控制器的子控制器之后会调用的方法,前提-->系统添加子控制器(例如设置导航控制器的根控制器),自定义添加需要手动调用(根据需求决定是否调用),或者自定义控制器从父控制器上移除时系统会自动调用

视图消失

  • 条件:设置View尺寸时用到的屏幕较大且有父控件, 而View本身较小,导致在运行在较小的屏幕上时View"消失"(实际上是随父控件等比例缩小)

  • 解决:view.autoresizingMask = UIViewAutoresizingNone;

(知识点琐碎,最后2天时间梳理)


  • 了解内部机制 :

---- NotificationCenter ---- 5天 --- 结束时间 : 8.21
---- CFNetwork ---- 10天 --- 结束时间 : 8.30

  • 不做重点,为以后开发做准备 :

    • Security
    • MapKit
    • XCTest

相关文章

网友评论

      本文标题:iOS官方文档阅读记录

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