iosMRC手动计数管理

428 阅读2分钟

OC对象的内存管理 MRC手动内存管理

  • 在iOS中,使用引用计数来管理OC对象的内存,基本数据类型不需要内存管理。
  • 一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间
  • 调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1
  • 内存管理的经验总结
    • xxx.retainCount //查看引用计数。

    • 当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不需要这个对象时,要调用release或者autorelease来释放它

    • 想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1

  • 实践
  • 关闭自动引用计数管理 image.png
  • 最基本的手动引用计数管理 image.png
  • 由于无法确认在什么时候释放内存比较好使用 autorelease 会自动释放
void test()
{
    // 内存泄漏:该释放的对象没有释放
//    MJPerson *person1 = [[[MJPerson alloc] init] autorelease];
//    MJPerson *person2 = [[[MJPerson alloc] init] autorelease];
}

  • 类与类之间是互相关联的时候怎么使用
  • 假设person中拥有dog成员属性的时候,这个dog要怎么管理内存呢
  • 源码
- MJPerson.h
#import <Foundation/Foundation.h>
#import "MJDog.h"

@interface MJPerson : NSObject
{
    MJDog *_dog;
    int _age;
}

- (void)setAge:(int)age;
- (int)age;

- (void)setDog:(MJDog *)dog;
- (MJDog *)dog;
@end

- MJPerson.m 
#import "MJPerson.h"

@implementation MJPerson

- (void)setAge:(int)age
{
    _age = age;
}

- (int)age
{
    return _age;
}

- (void)setDog:(MJDog *)dog
{
    if (_dog != dog) {
        [_dog release];
        _dog = [dog retain];
    }
}

- (MJDog *)dog
{
    return _dog;
}

- (void)dealloc
{
//    [_dog release];
//    _dog = nil;
    self.dog = nil; //调用了set方法释放了内存。
    
    NSLog(@"%s", __func__);
    
    // 父类的dealloc放到最后
    [super dealloc];
}

@end

- MJDog.h
#import <Foundation/Foundation.h>

@interface MJDog : NSObject

- (void)run;

@end
- MJDog.m
#import "MJDog.h"

@implementation MJDog

- (void)run
{
    NSLog(@"%s", __func__);
}

- (void)dealloc
{
    [super dealloc];
    
    NSLog(@"%s", __func__);
}

@end
- MJDog.h
#import <Foundation/Foundation.h>

@interface MJDog : NSObject

- (void)run;

@end
- MJDog.m
#import "MJDog.h"

@implementation MJDog

- (void)run
{
    NSLog(@"%s", __func__);
}

- (void)dealloc
{
    [super dealloc];
    
    NSLog(@"%s", __func__);
}

@end



  • 调用
void test2()
{
    MJDog *dog = [[MJDog alloc] init]; // 1
    
    MJPerson *person1 = [[MJPerson alloc] init];
    [person1 setDog:dog]; // 2
    
    MJPerson *person2 = [[MJPerson alloc] init];
    [person2 setDog:dog]; // 3
    
    [dog release]; // 2
    
    [person1 release]; // 1
    
    [[person2 dog] run];
    [person2 release]; // 0
}

  • 替换属性 旧的先释放,新的在+1. image.png
  • 分析
    • 1.MJDog *dog = [[MJDog alloc] init]; // 1 dog类计数1
    • 2.[person1 setDog:dog]; 调用 -> _dog = [dog retain]; //dog 计数+1 = 2
    • 3.[person2 setDog:dog]; // 3
    • 4.[dog release]; // 2 对应了第一条创建的指令 -1后=2
    • 5.[person1 release]; // 1 [person2 release]; // 0 person类自己计数减一后调用自身的dealloc,将person中的拥有的成员变量的引用计数-1,所以dog分别减了2次最后dog类引用计数变成为0,释放了内存。
  • 优化代码
- MJPerson.h
#import <Foundation/Foundation.h>
#import "MJDog.h"

@property (nonatomic, assign) int age; //assign 是直接赋值的意思。
@property (nonatomic, retain) MJDog *dog; //对象类型使用,对象被替换时,会自动判断后再赋值。释放旧的内存-1,对新的内存+1。注意点:delloc的时候要把成员变量设置为nil.

+ (instancetype)person;
@end
- MJPerson.m
#import "MJPerson.h"

@implementation MJPerson

+ (instancetype)person
{
    return [[[self alloc] init] autorelease];
}

- (void)dealloc
{
    self.dog = nil;
    self.car = nil;
    NSLog(@"%s", __func__);
    [super dealloc];
}

@end