OC - 第九章 内存管理( 初级 )

//                  第九章 内存管理(初级)

//   一、ios应用程序造成的Crash的主要原因就是内存问题, 内存问题分两种:
//        (1)、内存溢出:
//        (2)、野指针异常: 对象内存空间已经被系统回收, 仍然使用指针操作这块内存(crash的主要原因)

//   二、常见的内存管理方式有: GC、MRC、ARC:
//        (1)、GC: java采用的内存管理方式
//        垃圾回收机制: 由程序员开辟空间, 不需要用代码释放, 系统判断空间哪些内存不在被使用, 并回收这些内存  每次释放需要4 - 8倍的空闲内存;
//        (2)、IOS采用的是引用计数: 引用计数就是来标记当前使用的个数
//            分为 MRC 人工引用计数(对内存的控制更加灵活, 对程序员要求比较高)
//                ARC(基于MRC) 自动引用计数(编译器帮程序员默认加了释放的代码)

//   三、引用计数, 记录某块内存有几个引用(0时对象释放所占的资源)
        //影响引用计数的方法:
        //          (1)alloc retain copy 引用计数加1
        //          (2)release autorelease 引用计数减1

//  alloc
        Person *per = [[Person alloc]init];//alloc使引用计数加1
        NSLog(@"per的引用计数: %lu", per.retainCount);
        //从引用计数的角度: alloc 是引用计数 从 0 到 1
        //从对象的角度: 对象从无到有的过程

//  retain
        Person *per1;
        [per1 retain];//没有对象 相当于[nil retain]
        NSLog(@"per1的引用计数: %lu", per1.retainCount);//奔溃, 并没有分配内训空间

        //此时per 和 per2 指向的是同一块内存空间
        Person *per2 = [per retain];//引用计数加1
        NSLog(@"per 的引用计数: %lu", per.retainCount);
        NSLog(@"per2 的引用计数: %lu", per2.retainCount);
//  copy
        //基本上对象类型都有<NSCopying>
        Person *per3 = [per copy];//程序奔溃, 自动调用 copyWithZone
        //遵守NSCopying 协议 的对象才能Copy
        NSLog(@"per 的引用计数: %lu, per3 的引用计数:%lu",per1.retainCount, per3.retainCount);

        NSArray *arr = @[@"1", @"2", @"3"];
        NSLog(@"arr 的引用计数: %lu", arr.retainCount);//1
        NSLog(@"%p", arr);
        NSArray *arr1 = [arr copy];
        NSLog(@"arr1 的引用计数: %lu", arr1.retainCount);
        NSLog(@"%p , %p", arr, arr1);

        [per release];//引用计数减1
        NSLog(@"per 的引用计数: %lu",per.retainCount);

        //引用计数为1的时候再次进行release系统就会回收这块内存, 但是打印引用计数仍为1
        [per2 release];
        NSLog(@"per2 的阴影计数: %lu",per2.retainCount);//此时per2 指向的内存已经被回收, 再获取引用计数已经没有意义

//    四、内存管理的原则:
        //  (1). 有加就有减 看到alloc retain copy 就要在合适的地方进行release
        //  (2). 谁引起引用计数的增加, 就由谁来进行release

        //autorelease
        {
            //在未来的某个时刻让引用计数 -1, 指的是出自动释放池(autoreleasepool)
            Person *per = [[Person alloc]init];
            [per retain];
            [per retain];
            //(1) NSAutoreleasepool
            NSAutoreleasePool *autoRepopl = [[NSAutoreleasePool alloc]init];

            //autorelease并不会引起引用计数的变化
            [per autorelease];//出现在两种之间, 相当于先进后出, 进出栈
            NSLog(@"per 的引用计数: %lu",per.retainCount);
            [autoRepopl release];//此时 autorelease 的对象引用计数 - 1
            NSLog(@"per - 1 的引用计数: %lu",per.retainCount);

            //(2) @autoreleasepool 代码块
            @autoreleasepool {
                [per autorelease];
                NSLog(@"per 的引用计数:%lu", per.retainCount);
            }//出代码块时 autorelease 的对象引用计数 - 1 自动释放池向各对象发送release信息
            NSLog(@"per - 2 的引用计数:%lu", per.retainCount);

            [per release];
            //[per autorelease];
        }

//    五、dealloc
//        内部实现方法: 引用计数由1变成0的时候, 系统会自动调用本方法, 来回收内存, 不需要手动调用
        -(void)dealloc{
            [super dealloc];
        }
        //由于dealloc方法是重写的父类,所以重写此方法的时候,一定要把父类的方法内容也写上

//     六、Copy
//        分类  (1)copy、mutableCpoy
//             (2)不可变数组   可变数组
//             (3)浅拷贝: 相当于retain, 仅仅是让引用计数 + 1,并未开辟新的内存空间
//                深拷贝: 重新开辟一块新的空间, 将拷贝的对象的内容复制到这块空间中, 产生一个新的对象


        // 1.不可变copy去拷贝不可变数组 浅拷贝 相当于retain;
        {
            NSArray *arr = @[@"sfew",@"sfawe",@"ryh"];
            NSArray *arrCopy = [arr copy];
            NSLog(@"%lu %lu",arr.retainCount,arrCopy.retainCount);
            NSLog(@"%p %p",arr,arrCopy);
            NSLog(@"%@",[arrCopy class]);
        }
        // 2.不可变copy去拷贝可变数组  深拷贝
        {
            NSMutableArray *arr = @[@"长得好看有什么用", @"他学习又不好"].mutableCopy;
            NSMutableArray *arr1 = [NSMutableArray arrayWithObjects:@"嘿嘿嘿",  @"呵呵呵", nil];
            NSMutableArray *arrcopy = arr1.copy;
            //拷贝的返回值跟拷贝的对象没有关系, 而是取决于copy本身, 如果是不可变copy返回值是不可变的, 如果是mutableCopy,返回值就是可变的
            NSLog(@"arr1 引用计数: %lu, arrcopy 引用计数: %lu",arr1.retainCount, arrcopy.retainCount);
            NSLog(@"%p, %p", arr1, arrcopy);
//            [arrcopy addObject:@"我就呵呵呵呵"];arrcopy本质是不可变数组, 错误写法
            NSLog(@"%@",[arrcopy class]);//打印arrcopy的类型

        }
        // 3.可变的Copy拷贝不可变的数组  深拷贝
        {
            NSArray *arr = @[@"aregr",@"EFW"];
            NSMutableArray *MARR = [arr mutableCopy];
            NSLog(@"%lu %lu",arr.retainCount,MARR.retainCount);
            NSLog(@"%@",[MARR class]);
            if ([MARR isKindOfClass:[NSMutableArray class]]) {
                NSLog(@"可变数组");//这里不能判断是否是 不可变类型, 因为可变继承不可变
            }
        }
        //  4.可变的Copy拷贝可变的数组  深拷贝
        {
            NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"farwg",@"arwg", nil];
            NSMutableArray *Marr = mArr.mutableCopy;
            NSLog(@"%lu %lu",mArr.retainCount,Marr.retainCount);
            NSLog(@"%@",[Marr class]);
        }

        // 自定义类的Copy
        {
            Person *per = [[Person alloc]init];
            per.name = @"awrg";
            per.hobby = @"agdsv";
            Person *perCopy = per.copy;
            NSLog(@"%@ %@",perCopy.name,perCopy.hobby);
            [per release];
            [perCopy release];

        }

        //自定义的mutableCopy
        {
            Person *per = [[Person alloc]init];
            per.name = @"awrg";
            per.hobby = @"agdsv";
            Person *perCopy1 = [per mutableCopy];
            NSLog(@"%@ %@",perCopy1.name,perCopy1.hobby);
            [per release];
            [perCopy1 release];
        }

        //浅拷贝的实现
        -(id)copyWithZone:(NSZone *)zone{

            return [self retain];//浅拷贝
        }

        //深拷贝的实现
        -(id)mutableCopyWithZone:(NSZone *)zone{

            Person *per = [[Person alloc]init];
            per.name = self.name;
            per.age = self.age;
            return per;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值