美文网首页
小知识总结:

小知识总结:

作者: y夜无眠 | 来源:发表于2018-08-17 14:26 被阅读0次

    __block 和 __weak 的区别:

    • __block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
    • __weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
    • __block对象可以在block中被重新赋值, __weak不可以.
    • __block对象在ARC下可能会导致循环引用, 非ARC下会避免循环引用, __weak只在ARC下使用, 可以避免循环引用.

    assign 和 weak 的区别

    assign 平时只是用在基本类型的的修饰,比如NSInteger,float等

    weak主要用在对象上,其中尤以代理用的多,几乎都是用weak; 自身已经对它进行一次强引用,没有必要再强引用一次时也会使用weak。比如:自定义 IBOutlet控件属性一般也使用weak,当然也可以使用strong...

    weak修饰的对象不增加引用计数,被释放后自动置为nil,而assign修饰的对象属于指针赋值,也不会增加引用计数,但是在对象被释放后,assign修饰的这个变量并不会自动置为nil, 指针的地址还是存在的, 所以会导致野指针 (对象一般分配在堆上的某块内存,如果在后续的内存分配中,刚好分到了这块地址,程序就会崩溃掉。)

    那为什么可以用assign修饰基本数据类型?因为基础数据类型一般分配在栈上,栈的内存会由系统自己自动处理,不会造成野指针。

    copy 与 深. 浅拷贝

    • copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等)
    • mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)

    深拷贝 与 浅拷贝

    • 深拷贝 : 拷贝出来的对象与源对象地址不一致! 这意味着我修改拷贝对象的值对源对象的值没有任何影响.
    • 浅拷贝 : 拷贝出来的对象与源对象地址一致! 这意味着我修改拷贝对象的值会直接影响到源对象.

      image.png

    为什么block要用 copy

    block是一个对象, 所以block理论上是可以retain/release的. 但是block在创建的时候它的内存是默认是分配在栈(stack)上, 而不是堆(heap)上的. 所以它的作用域仅限创建时候的当前上下文(函数, 方法...), 当你在该作用域外调用该block时, 程序就会崩溃.

    RunLoop

    当定时器 Timer 加到 mode 为 kCFRunLoopDefaultMode 时,拖拽 UITextview 时候 Timer 就不起作用了;当 mode 为 kCFRunLoopCommonModes 时,拖拽 UITextview 不影响 Timer 的使用...

    • 一个线程对应一个RunLoop,RunLoop里面有若干个mode,每个mode都有自己的内容,Source/Timer/Observer等等。而RunLoop有了mode才会有效果。注意:mode里面必须要有内容!!!

    • 要让RunLoop跑起来,既要有有内容的mode,也需要 [[NSRunLoop currentRunLoop] run]; 。两个都不可少。

    • RunLoop跑起来后相当于是一个while的死循环,后面的代码不会执行。

    GCD

    • GCD的好处
    • GCD 可用于多核的并行运算
    • GCD 会自动利用更多的 CPU 内核(比如双核、四核)
    • GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
    • 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码
    • GCD的几种情况:
    • 同步任务 + 并发队列 : 没有开启新线程,串行执行任务
    • 异步任务 + 并发队列 : 有开启新线程,并发执行任务
    • 同步任务 + 串行队列 : 没有开启新线程,串行执行任务
    • 异步任务 + 串行队列 : 有开启新线程(1条),串行执行任务
    • 同步任务 + 主队列 : 主线程调用:死锁卡住不执行; 其他线程调用:没有开启新线程,串行执行任务
    • 异步任务 + 主队列 : 没有开启新线程,串行执行任务
    • GCD 栅栏方法:dispatch_barrier _async

    在执行完栅栏前面的操作之后,才执行栅栏操作,最后再执行栅栏后边的操作。

    特别注意: 不能用全局队列: dispatch _get _global _queue , 只能用: dispatch _queue _create 来创建

    • GCD 延时执行方法:dispatch_after

    • GCD 一次性代码(只执行一次):dispatch_once

    • GCD 快速迭代方法:dispatch_apply : 按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。

    • GCD 队列组:dispatch_group

    • dispatch _group _notify : 当所有任务都执行完成之后,才执行dispatch _group _notify block 中的任务。
    • dispatch _group _wait : 暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行。
    • dispatch _group _enter、dispatch _group _leave :
    • GCD 信号量:dispatch_semaphore

    作用:

    • 保持线程同步,将异步执行任务转换为同步执行任务
    • 保证线程安全,为线程加锁

    进程与线程

    程序是一个可以运行的文件, 一个程序至少有一个进程, 一个进程至少有一个线程, 即主线程.

    进程

    • 正在进行的程序被称为进程, 负责程序运行的内存分配, 每个进程都有自己的独立虚拟内存空间, 一个程序的一次运行, 在执行过程中拥有独立的内存单元, 而多个线程共享一个内存.

    线程

    • 线程是进程中的基本单元(可执行的代码段), 线程可以并发运行, 提高执行效率
    • 创建线程的目的: 就是为了开启一条新的可执行的代码段, 与主线程中的代码实现同时运行, 防止界面假死, 是实现异步的技术的主要手段, 比如网络异步下载...

    多线程开发的优缺点:

    • 好处:
      • 使用多线程可以把程序中占据时间长的任务或耗时操作放到后台去处理, 如图片 视频的下载;
      • 发挥多核处理器的优势, 并发执行让系统运行的更快, 更流畅, 用户体验更好;
    • 缺点:
      • 资源竞争, 线程安全的问题: 多个线程会对同一资源出现争夺;
      • 内存消耗: 更多的线程需要更多的内存空间;
      • 大量的线程降低代码的可读性;
      • 死锁;

    空指针和野指针

    • 空指针: 没有存储任何内存地址的指针;

    • 野指针: 存储不可用的内存地址(或不存在的内存地址, 如已被收回释放) 的指针, 指向的内存地址不可用会报错;

    • 僵尸指针: 野指针的一种情况, 即该指针指向的对象已经被释放, 但是却没有对当前指针赋值为 nil ;

    • 僵尸对象: 使用已经被释放了的对象, 若使用了一般会报错: unrecognized selector sent to instance ;

    宏与const的区别:

    • 宏(define) : 宏只是进行简单的文本替换, 没有类型, 也不会作类型检查, 不会报编译错误, 宏是预编译(编译之前处理), 若大量使用宏, 容易造成编译时间久; 宏还能定义一些函数, 方法, const不能;

    • const: 定义常量, 会有类型检查; 它是在编译运行阶段使用, 会报编译错误;

    static 的作用:

    • static 声明局部变量: 则改变变量的存储方式(生命周期), 使变量成为表态的局部变量, 即编译时就为变量分配内存, 直到程序退出才释放存储单元. 这样 使得该局部变量有记忆功能, 可以记忆上次的数据, 不过由于仍是局部变量, 因而只能在代码内部使用(作用域不变).

    • static 声明外部变量: 为了限制某些外部变量的作用域 (外部变量指在所有代码块 {} 之外定义的变量, 它本身是静态变量, 编译时分配内存, 程序结束时释放内存单元. 同时, 其作用域很广, 整个文件都有效, 甚至别的文件也能引用它 ) , 使其只在本文件中有效, 而不能被其他文件引用, 可以用 static 关键字对其作出声明.

    swfit 和 oc 的区别

    1. Swift对数据要求严格,不存在隐式转换,强制转换格式:int(a);
    2. swift 使用 private 修饰后, 是用运行时也不能获取其属性或函数, 而 oc 则可能...
    3. nil 指针的使用: swift 中 nil 也是一种类型(可选类型值会 nil), 莫名调用会报错, OC则不会...
    4. swift 还有命名空间, 泛型, 可选类型 的概念;

    @synthesize和@dynamic 的区别

    • @property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
    • @synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
    • @dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定
    • @dynamic其主要的作用就是用在NSManageObject对象的属性声明上,由于此类对象的属性一般是从Core Data的属性中生成的,Core Data框架会在程序运行的时候为此类属性生成getter和Setter方法

    动态库 和 静态库

    • 动态库: .dylib 和 .framework
    • 静态库: .a 和 .framework
      系统的.framework是动态库,我们自己建立的.framework是静态库。

    instancetype 和 id 的区别

    • 相同点:

    都可以作为方法的返回类型

    • 不同点:
    • instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
    • instancetype : 编译时判断数据类型; - id : 编译器不检查类型, 运行时检查类型
    • id可以作为方法的参数,但instancetype不可以, instancetype只适用于初始化方法和便利构造器的返回值类型

    Smalltalk : 被称为 "面向对象编程之母"

    imageNamed 和 imageWithContentOfFile的区别

    • 使用imageNamed:加载图片
    1. 加载到内存后, 会一直停留在内存中, 不会随着对象销毁而销毁;
    2. 加载进图片后, 战胜的内存归系统管理, 我们无法管理;
    3. 相同的图片, 图片不会重新加载;
    4. 加载到内存后, 占据内存空间较大;
    • 使用 imageWithContentOfFile 加载图片
    1. 加载到内存中后, 占据内存空间比较小;
    2. 相同的图片会被重新加载到内存中;
    3. 对象销毁的时候, 加载到内存中的图片会被一起销毁
    结论:
    • 如果图片较小,并且频繁使用的图片,使用imageName:来加载图片(按钮图片/主页图片/占位图)
    • 如果图片较大,并且使用次数较少,使用 imageWithContentOfFile:来加载(相册/版本新特性)

    NSCache

    • NSCache 的特点:
    • NSCache是线程安全的
    • 在内存不足时NSCache会自动释放存储的对象
    • NSCache的键key不会被复制,所以key不需要实现NSCopying协议
    • NSCache缓存对象自身被释放
    • 手动调用removeObjectForKey:方法
    • 手动调用removeAllObjects
    • 缓存中对象的个数大于countLimit,或,缓存中对象的总cost值大于totalCostLimit
    • 程序进入后台后
    • 收到系统的内存警告

    几种常用的锁 ( iOS 中几种常用的锁总结 )

    @synchronized
    NSLock 对象锁
    NSRecursiveLock 递归锁
    NSConditionLock 条件锁
    pthread_mutex 互斥锁(C语言)
    dispatch_semaphore 信号量实现加锁(GCD)

    UIView 的 setNeedsDisplay 与 setNeedsLayout 方法

    两个方法都是异步执行的;

    • setNeedsDisplay:

    setNeedsDisplay 会自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext

    • setNeedsLayout:

    setNeedsLayout会默认调用layoutSubViews,可以调整子视图的尺寸和位置;

    一些UIView方法的调用情况

    NSNumber 与NSValue

    • 由于集合里只能存放对象,不可以存放基本数据类型,所以我们有时候需要讲一些对象比如基本数据类型,结构体等存到NSDictionary NSArray中,我们就需要将这些数据类型或结构体包装成OC对象,以便集合能访问到。常用的用来包装这些类型的有NSNumber NSValue
    1. NSNumber只能包装基本数据类型,比如int, float,char,BOOL等
    2. NSValue可以包装任意一个对象,包括系统自定义的数据结构,结构体等等
    3. NSNumber是NSValue的一个子类

    nil / Nil / NULL / NSNull的区别 ( 参考 )

    • nil : 用于表示指向Objective-C中对象的指针为空
    NSString *string = nil;
    
    • Nil : 用于表示Objective-C类(Class)类型的变量值为空
    Class anyClass = Nil;
    
    • NULL: NULL表示C指针为空
    char * c = NULL;
    
    • NSNull: 一个Objective-C类
    NSArray *arr = [NSArray arrayWithObjects:@"wang",@"zz",[NSNull null],@"foogry"];
    

    内存分区情况

    1. 代码区: 用来存放函数、二进制代码及最静态的东西;
    2. 数据区: 系统运行时申请内存并初始化, 系统退出时由系统释放; 存放全局变量, 静态变量, 常量;
    3. 堆区: 通过malloc 等函数 或 new 等操作符动态申请得到, 需要程序员手动申请和释放;
    4. 栈区: 函数模块内申请, 函数结束时由系统自动释放; 存放局部变量, 函数参数, 结构体中创建的变量也在栈中。
    • 内存泄漏:

    用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元,不能被任何程序再次使用,直到程序结束。即所谓内存泄漏。简单的说就是申请了一块内存空间,使用完毕后没有释放掉。
    它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。

    注意:内存泄漏是指堆内存的泄漏。
    • 内存溢出:

    内存溢出就是在程序运行的过程中如果一次需要读取的数据超过这个栈内存大小的话就会出现溢出.所以一般内存管理中,需要生成一个对象释放一个对象,你想对这个对象执行的操作写在生成和释放之间.

    • 野指针:

    对象内存空间已经被系统回收,仍然使⽤指针操作这块内存。野指针异常是程序crash的主要原因。

    iOS系统架构 参考链接

    iOS的系统架构分为四层,由上到下一次为:可触摸层(Cocoa Touch layer)、媒体层(Media layer)、核心服务层(Core Services layer)、核心操作系统层(Core OS layer)

    影响app性能的几个方面 参考链接

    • 网络性能:
    • 内存问题:
    • 主线程阻塞:
    • Offscreen rendering(离屏渲染):
    • 图片的处理:

    self 和 super 的区别: 参考文章

    self : 关键字, 代表当前方法的调用者

    • 如果是类方法, 代表当前类
    • 如果是实例方法, 代表当前类的对象

    super :编译器指令

    • 经典题目:
    @implementation Son : Father
    - (id)init
    {
        self = [super init];
        if (self)
        {
            NSLog(@"%@", NSStringFromClass([self class]));   //  返回 Son
            NSLog(@"%@", NSStringFromClass([super class]));  // 返回 Son
        }
        return self;
    }
    @end
    
    

    TabelView的性能优化: 参考链接

    1. 行高一定要缓存! ( 因为 heightForRowAtIndexPath: 是调用最频繁的方法 )
    2. 不要动态创建子视图,所有的子视图都预先创建,如果不需要显示可以设置Hidden;
    3. 所有的子视图都应该添加到 contentView上;
    4. 所有的子视图都必须指定背景颜色, 且所有的颜色都不要 alpha;
    5. 异步加载图片;
    6. 离屏渲染的问题

    UIView动画与核心动画的区别?

    • 核心动画只作用在 layer 上;
    • 核心动画修改的值都是假像, 它的真实位置没有发生变化
    • 什么时候用 UIView动画 ?

    当需要与用户交互时用 UIView, 不需要与用户交互时两个都可以...

    • 什么情况用核心动画 ?
    • 转场动画.
    • 帧动画.
    • 动画组.

    问题: 触摸事件的传递顺序 以及 寻找最合适的 view 的方法....

    相关文章

      网友评论

          本文标题:小知识总结:

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