学习内容

欢迎关注我的iOS学习总结——每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary

  1. iOS的内存管理和引用计数规则

    • 内存管理的思考方式

      • 自己生成的对象自己持有
      • 非自己生成的对象自己也能持有
      • 自己持有的对象不需要时释放
      • 非自己持有的对象不能释放
    • ARC有效时,id类型和对象类型必须加上所有权修饰符,一共有四种

      • __strong

        • id和对象类型如果不加所有权修饰符那么默认为__strong类型

        • id obj = [[NSObject alloc]init]
          id __strong obj = [[NSObject alloc]init]
          //以上两种在ARC有效情况下是相同的
        • //ARARC
          {
          id __strong obj = [[NSObject alloc]init]
          }
          //ARC无效时
          {
          id obj = [[NSObject alloc]init]
          [obj release]
          }
          //ARC无效时执行release操作
        • __strong修饰符表示对对象的强引用,持有强引用的变量在超出其作用域时被废弃,它强引用的对象也会被释放

        • 含有__strong修饰的变量,不仅仅在作用域上,在赋值上也能正确管理对象的生命周期

      • __weak

        • __strong所有权修饰符大部分情况下可以完美的进行内润管理,但是引用计数式内存管理方法必然会遇到循环引用,这时候就需要使用__weak来解决
        • 循环引用会造成内存泄漏,所谓内存泄漏就是应当被废弃的对象在超出其生存周期(作用域)后继续存在
        • __weak修饰的变量不持有对象,原对象在超出其作用域时会被立即释放
        • 通过检查__weak修饰符的变量是否为nil,可以判断被赋值的对象是否已经被释放
      • __unsafe_unretained

        • 这是不安全的所有权修饰符
        • 附有__unsafe_unretained的变量不属于编译器的内存管理对象
        • 如果对象已经被释放,但是__unsafe_unretained修饰的变量仍然访问了原对象的内存,那么这个变量就是个悬垂指针,错误访问,大概率会引起程序的崩溃
      • __autoreleasing

        • 在ARC有效时,用@autoreleasepool块代替NSAutoreleasePool类,用附有__autoreleasing修饰符的变量来代替autorelease方法
        • 编译器会自动检查方法名是否为alloc/new/copy/mutablecopy开头,如果不是的话则自动将返回值的对象注册到autoreleasepool中(init方法返回值的对象也不注册到autoreleasepool中)
    • 属性声明的属性修饰符与所有权修饰符之间的关系

      • 属性修饰符 _unsafe_unretained
        assign _unsafe_unretained
        copy _strong(指针变量指向的是新的被复制的对象)
        retain _strong
        strong _strong
        unsafe_unretained _unsafe_unretained
        weak _weak
      • 为属性添加各种修饰符就相当于给变量添加各种对应的所有权修饰符

      • @property (strong) id obj;
        --------------------------
        id __strong obj = [[NSObject alloc]init]
    • ARC的规则

      • 不能使用retain/retainCount/release/autoRelease
      • 不能使用NSAllocateObject和NSDeallocateObject
      • 遵守内存管理的方法命名规则
      • 不要显式的调用dealloc
      • 使用@autoreleasepool代替NSAutoreleasePool
      • 不能使用NSZone
      • 对象型变量不能作为c语言结构体的成员
      • 显式转换"id"和"void *"
  2. Block

    • block是什么

      • //一句话概括,block是带有自动变量的匿名函数
        ^(int param){
        NSLog(@"%d",param);
        }
        -------------------------------------
        //上面的为简写的,完整的block形式为
        //^返回值类型 (参数列表){表达式}
        ^void (int param){
        NSLog(@"%d",param);
        }
        //完整形式的block语法与C语言函数定义相比,仅有两点不同
        //1.没有函数名---没有函数名因为它是匿名函数
        //2.带有"^"符号---^是插入记号,方便查找
      • block的返回值类型可以省略,省略返回值类型时

        • 如果表达式中有return语句,那么返回值类型就和return的相同
        • 没有return,返回值类型就是void
        • 有多个return语句时,所有return的类型必须相同
      • block的参数类型也可以省略

        • ^(void)(void){expression}
          -------------------------
          ^{expression}
      • //C语言的函数指针的写法
        int func(int a){
        printf("%d",a);
        }
        int (*funcptr)(int) = &func //将func函数的地址赋值给函数指针funcptr //block的写法
        int (^blk)(int a); //仅仅是将c语言函数指针的"*"更换成了"^"
      • block类型变量与c语言变量的用法完全相同,可以作为以下用途使用

        • 自动变量(局部变量)
        • 函数参数
        • 静态变量
        • 静态全局变量
        • 全局变量
      • block变量的使用

        • //将block赋值给block变量
          int (^blk)(int) = ^(int){};
          //将block变量赋值给block变量
          int (^blk1)(int) = blk;
          //两个block变量互相赋值
          int (^blk2)(int);
          blk2 = blk1;
        • //在函数参数中使用block类型变量可以向函数传递block
          void func((int)(^blk)(int));
          //在函数返回值中使用block可以将返回值指定为block
          void func(){
          return ^{return;};
          }
        • //使用typedef定义block
          typedef (int)(^blk)(int); //定义一个block,后面该block的类型就为blk
          //通过block类型变量调用block与在c语言中通常的函数执行没什么区别
          blk func(blk block,int rate){
          return blk(rate);
          }
        • //这里blk截获的是Array对象的实例指针,通过这个实例指针调用该对象的方法是完全没问题的,但是如果向Array指针赋值的话就会编译错误(可以用__block解决)
          id Array = [NSMutableArray new];
          void (^blk)(void) = ^{
          id obj = [NSObject new];
          [Array addObject:obj];
          };
        • 在block中如果需要改变被截获的外部变量的值,可以使用__block说明符(__block存储域类说明符)来解决

        • block代码转换为cpp代码分析(待完善)

          //block对外部变量捕获的原理,使用cpp代码查看
          //这里写一个block捕获外部变量val的值
          int val = 10;
          void (^blk)(void) = ^{
          printf("%d",val);
          };
          //block本质也是一个OC的对象,oc对象都是结构体,其中含有指向父类的isa指针
          struct __main_block_impl_0 {
          struct __block_impl impl;
          struct __main_block_desc_0* Desc;
          int val;
          __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
          impl.isa = &_NSConcreteStackBlock;
          impl.Flags = flags;
          impl.FuncPtr = fp;
          Desc = desc;
          }
          };
          //这里使用clang -rewrite-objc将.m代码转换成.cpp代码,这里的_cself是block的自身的结构体指针,可以看到在block的函数中是将val重新创建了一个变量进行输出
          static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
          int val = __cself->val; // bound by copy
          printf("%d",val);
          }
        • 三种block的形式

          1. NSConcreteGlobalBlock(全局Block,存放在全局区[数据区])

            • 记录全局变量的地方有Block语法时
            • Block语法的表达式中不使用应截获的自动变量时
          2. NSConcreteStackBlock(栈Block)

            • 除了1.中的两种情况生成的Block,其他使用Block语法产生的Block都是栈Block
          3. NSConcreteMallocBlock(堆Block)

            • 配置在全局区的block在变量作用域外也可以通过指针安全的访问,但是配置在栈上的block一旦其作用域结束就会被系统回收

            • Block提供了将Block和__Block变量复制到堆上的方法来解决这个问题

            • 复制到堆上的block将类对象NSMallocBlock赋值给isa指针

              struct __main_block_impl_0 {
              struct __block_impl impl;
              struct __main_block_desc_0* Desc;
              __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
              //注意这里就是讲isa指针指向堆Block
              impl.isa = &_NSConcreteStackBlock;
              }
              };

iOS的内存管理和引用计数规则、Block的用法以及三种形式(stack、malloc、global)的更多相关文章

  1. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  2. Objective-C内存管理之-引用计数

    本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...

  3. Swift基础语法-内存管理, 自动引用计数

    1. 工作机制 Swift和OC一样,采用自动引用计数来管理内存 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1 当该强引用消失时,引用计数会自动-1 当引用计数为0时,该对象会被销毁 2 ...

  4. Python内存管理及引用计数

    作为一门动态语言,python很重要的一个概念就是动态类型,即对象的类型和内存占用都是运行时确定的.(Why?)运行时,解释器会根据语法和右操作数来决定新对象的类型.动态类型的实现,是通过引用和对象的 ...

  5. 理解 iOS 的内存管理

    远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳 ...

  6. iOS ARC内存管理

    iOS的内存管理机制,只要是iOS开发者,不管多长的时间经验,都能说出来一点,但是要深入的理解.还是不简单的.随着ARC(自动管理内存)的流行.iOS开发者告别了手动管理内存的复杂工作.但是自动管理内 ...

  7. iOS的内存管理

    在Objective-C 这种面向对象的语言里,内存管理是个重要的概念.要想用一门语言写出内存使用效率高而且又没有bug的代码,就得掌握其内存管理模型的种种细节. 一旦理解了这些规则,你就会发现,其实 ...

  8. iOS项目转移到自动引用计数

    这里主要参考了Apple官方文档:Transitioning to ARC Release Notes 在支持iOS5的Xcode4中,创建项目会看到这样的选项: 这是iOS5的新特性,自动对象引用计 ...

  9. IOS中内存管理机制浅解

    我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是 由系统自己管理的,放在栈上).如果一个对象创建并使用后没有得 ...

随机推荐

  1. TcxGrid

    一.列的宽度为64时,其宽度会自动根据字段的长度调整,设置其他值即为固定值: 二.cell中显示按钮:选中某列,在properties中更改为ButtonEdit,点击子属性buttons添加butt ...

  2. java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换

    java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换 一.字符串与其他类型连接 public class DemoString{ public static void mai ...

  3. 2020新Asp.NET敏捷快速开发框架7.0.5旗舰版源码asp.net mvc框架,工具类CRM,工作流

    演示地址: http://frame3.diytassel.com  用户名:system  密码:0000    需要的联系QQ:22539134 一.新添加了 1.多语言功能: 2.代码生成器模版 ...

  4. [linux] 小问题:管道符,换行问题等;[nginx]启动,重启,关闭命令;以及升级nginx切换命令

    Lniux换行问题 后面回车不会马上执行本条命令而是换行继续. : 是运行完前面就继续后面的, && 同样是前面正确就运行后面, || 是前面运行不正确就运行后面. | 管道符“|”将 ...

  5. Spring5:事务管理【整合Mybatis】

    Spring 整合Mybatis 1:导入依赖 <dependencies> <!--测试依赖--> <dependency> <groupId>jun ...

  6. Python修改paramiko模块开发运维审计保垒机

    目前市面上,专门做IT审计堡垒机的厂商有很多,他们的产品都有一个特点,那就是基本上每台的售价都在20万以上.像我们做技术的,不可能每次待的公司都是大公司,那么在小公司,是不太可能投资20多万买一台硬件 ...

  7. OAuth-授权机制

    一.应用场景 有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来.用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片. 问 ...

  8. Spark SQL源码解析(三)Analysis阶段分析

    Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Analysis阶段概述 首先 ...

  9. Docker安装MySql完整教程、实操

    docker:官网 docker:镜像官网:        镜像官网可以所有应用,选择安装环境:会给出安装命令,例如:docker pull redis 默认拉取最新的版本(指定版本:docker p ...

  10. Oracle把表记录恢复到指定时间节点

    可以执行以下命令alter table 表名 enable row movement; --开启表行移动flashback table 表名 to timestamp to_timestamp('20 ...