iOS基础知识

作者: horrybear | 来源:发表于2017-05-20 21:45 被阅读22次

    1. load方法和initialize方法

    相同点

    • 在不考虑开发者主动使用的情况下,系统最多会调用一次
    • 如果父类和子类都被调用,父类的调用一定在子类之前
    • 都是为了应用运行提前创建合适的运行环境
    • 在使用时都不要过重地依赖于这两个方法,除非真正必要

    load

    • 调用时间早于initialize,main函数之前,不会触发initialize的调用
    • 对于有依赖关系的类,要确保被依赖类的load优先调用
    • 没有load方法的实现,不会调用父类的的load方法
    • Category的load也会收到调用,顺序在主类之后
    • Method Swizzleu一般会放在load中执行

    initialize

    • 懒加载,第一次主动使用类时调用
    • 子类不实现initialize方法,会把父类的实现继承过来调用一遍
    • 都是线程安全的,不要再使用锁

    2.block

    数据结构

    struct Block_descriptor {
        unsigned long int reserved;
        unsigned long int size;
        void (*copy)(void *dst, void *src);
        void (*dispose)(void *);
    };
    struct Block_layout {
        void *isa;
        int flags;
        int reserved;
        void (*invoke)(void *, ...);
        struct Block_descriptor *descriptor;
        /* Imported variables. */
    };
    
    

    类型

    • _NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。
    • _NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
    • _NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

    变量的复制

    • block外变量的引用,是复制到数据结构中访问
    • __block修饰的外部变量,是复制其引用地址来实现访问

    ARC和MRC下的block

    配置在栈上的Block也就是NSStackBlock类型的Block,如果其所属的变量作用域结束该Block就会废弃。这个时候如果继续使用该Block,就应该使用copy方法,将NSStackBlock拷贝为NSMallocBlock。当NSMallocBlock的引用计数变为0,该NSMallocBlock就会被释放。
    如果是非ARC环境,需要显式的执行copy或者antorelease方法。
    而当ARC有效的时候,实际上大部分情况下编译器已经为我们做好了,自动的将Block从栈上复制到堆上。包括以下几个情况:

    1. Block作为返回值时,类似在非ARC的时候,对返回值Block执行[[returnedBlock copy] autorelease];
    2. 方法的参数中传递Block时
    3. Cocoa框架中方法名中还有useringBlock等时
    4. GCD相关的一系列API传递Block时

    对于非ARC下,为了防止循环引用,我们使用__block来修饰在Block中使用的对象。
    对于ARC下,为了防止循环引用,我们使用__weak来修饰在Block中使用的对象。

    循环引用和野指针

    block和对象互相强引用,引起引用循环,使用弱引用打破循环。block使用的对象被提前释放,产生了野指针,会引起crash,要注意对象的生命周期。

    参考链接
    谈Objective-C block的实现
    正确使用Block避免Cycle Retain和Crash

    3.ARC

    ARC是编译特性,不是垃圾回收,本质还是计数式内存管理,在ARC特性下有4种与内存管理息息相关的变量所有权修饰符值得我们关注:

    变量所有权修饰符 属性修饰符
    __strong copy retain strong
    __weak weak
    __autoreleasing N/A
    __unsafe_unretaied assign unsafe_unretained

    __autoreleasing

    在 ARC 模式下,我们不能显示的使用 autorelease 方法了

    __unsafe_unretained

    ARC 是在 iOS5 引入的,而 __unsafe_unretained 这个修饰符主要是为了在 ARC 刚发布时兼容 iOS4 以及版本更低的系统,因为这些版本没有弱引用机制

    关于 Toll-Free Bridging

    在 MRC 时代,由于 Objective-C 类型的对象和 Core Foundation 类型的对象都是相同的 release 和 retain 操作规则,所以 Toll-Free Bridging 的使用比较简单,但是自从切换到 ARC 后,Objective-C 类型的对象内存管理规则改变了,而 Core Foundation 依然是之前的机制,换句话说,Core Foundation 不支持 ARC。是苹果在引入 ARC 之后对 Toll-Free Bridging 的操作也加入了对应的方法与修饰符,用来指明用哪种规则管理内存,或者说是内存管理权的归属。这些方法和修饰符分别是:

    • __bridge(修饰符)-- 只是声明类型转变,但是不做内存管理规则的转变。
    • __bridge_retained(修饰符) or CFBridgingRetain(函数)-- 内存管理的责任由原来的 Objective-C 交给Core Foundation 来处理,也就是,将 ARC 转变为 MRC
    • __bridge_transfer(修饰符) or CFBridgingRelease(函数)-- 内存管理的责任由 Core Foundation 转交给 Objective-C,即将管理方式由 MRC 转变为 ARC。

    参考链接:
    iOS ARC 内存管理要点

    4.RunLoop

    概念

    线程能随时处理事件但并不退出的模型通常被称为Event Loop,RunLoop实际上是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。

    和线程的关系

    RunLoop和线程一一对应,RunLoop的创建发生在线程第一次获取时,只能在线程内获取自身的RunLoop(主线程除外)。苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。

    相关类

    CFRunLoopRef
    CFRunLoopModeRef
    CFRunLoopSourceRef
    CFRunLoopTimerRef
    CFRunLoopObserverRef
    一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。

    Mode

    系统默认注册了5个Mode:

    1. kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。
    2. UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
    3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
    4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
    5. kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。

    参考链接
    深入理解RunLoop

    5.UIView

    UIView继承于UIResponder类,因此它主要表达了两个意思
    1.可视(CALayer)
    2.可互交(UIResponder)
    每个UIView都有一个隐式层(implicit Layer),View本身就是这个隐式层的Delegate.
    Layer又有两部分组成。present layer和Model layer.
    present layer表示了中间的过程状态,而Model layer则表示了起始和结束状态

    loadView

    loadView在View为nil时调用,早于ViewDidLoad,通常用于代码实现控件,收到内存警告时会再次调用。loadView默认做的事情是:加载nib。如果你想自己创建View对象,那么可以重载这个方法。

    UIWindow

    1. UIWindow是一种特殊的UIView,通常在一个app中至少会有一个UIWindow。
    2. iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的View,最后将控制器的View添加到UIWindow上,于是控制器的View就显示在屏幕上了。
    3. 一个iOS程序之所以能显示在屏幕上,完全是因为它有UIWindow,也就是说,没有UIWindow就看不到任何UI界面。
    4. 状态栏和键盘都是特殊的UIWindow。

    UIWindow有三个层级,分别是Normal,StatusBar,Alert。

    keyWindow是指定的用来接收键盘以及非触摸类的消息,而且程序中每一个时刻只能有一个window是keyWindow。

    6.沙盒和bundle

    沙盒目录结构

    • Application:存放程序源文件,上架前经过数字签名,上架后不可修改
    • Documents:常用目录,iCloud备份目录,存放数据,这里不能存缓存文件,否则上架不被通过
      Library
    • Caches:存放体积大又不需要备份的数据,SDWebImage缓存路径就是这个
      Preference:设置目录,iCloud会备份设置信息
    • tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能

    App Bundle 里面有什么

    • Info.plist:此文件包含了应用程序的配置信息.系统依赖此文件以获取应用程序的相关信息
    • 可执行文件:此文件包含应用程序的入口和通过静态连接到应用程序target的代码
    • 资源文件:图片,声音文件一类的
    • 其他:可以嵌入定制的数据资源

    7.属性

    修饰符

    • atomic,nonatomic -- 原子性
    • readonly,readwrite -- 访问权限
    • assign,strong,weak,copy -- ARC内存管理
    • assign,retain,copy -- MRC内存管理
    • setter=,getter= -- 指定方法名称

    assign和weak的区别

    assign修饰的数据内存由系统清理,对于基础数据类型,生存周期为整个栈周期,可以由栈处理。修饰对象时,如果这个对象被其他过程释放(即指向的堆内存被释放),对象的指针地址依然存在,形成野指针。weak不能修饰基础类型数据,修饰对象时,如果对象被释放,指针会自动置为nil。

    实现原理

    在普通的OC对象中,@property就是编译器自动帮生成一个私有的成员变量和setter与getter方法的声明和实现

    protocol 和 category

    1. 在protocol中使用property只会生成setter和getter方法声明,我们使用属性的目的,是希望遵守我协议的对象的实现该属性
    2. category 使用 @property 也是只会生成setter和getter方法的声明,如果我们真的需要给category增加属性的实现,需要借助于运行时的两个函数

    objc_setAssociatedObject
    objc_getAssociatedObject

    8.cocoapods原理

    • 将所有的依赖库都放到另一个名为 Pods 项目中
    • Pods 项目最终会编译成一个名为 libPods.a 的文件,主项目只需要依赖这个 .a 文件即可。这样,依赖库源码管理工作都从主项目移到了 Pods 项目中。
    • 对于资源文件,CocoaPods 提供了一个名为 Pods-resources.sh 的 bash 脚本,该脚本在每次项目编译的时候都会执行,将第三方库的各种资源文件复制到目标目录中。
    • CocoaPods 通过一个名为 Pods.xcconfig 的文件来在编译时设置所有的依赖和参数。

    9. Instruments常用功能

    1. Time Profiler:性能分析
    2. Zombies:检查是否访问了僵尸对象
    3. Allocations:用来检查内存,写算法的那批人也用这个来检查
    4. Leaks:检查内存,看是否有内存泄露

    10.nil / Nil / NULL / NSNull

    标志 含义
    NULL (void *)0 C指针的字面零值
    nil (id)0 Objective-C对象的字面零值
    Nil (Class)0 Objective-C类的字面零值
    NSNull [NSNull null] 用来表示零值的单独的对象

    to be continued

    相关文章

      网友评论

      本文标题:iOS基础知识

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