//
// main.m
// OC_内存管理
//
// Created by YIem on 15/12/3.
// Copyright (c) 2015年 www.yiem.net YIem博客. All rights reserved.
//

import <Foundation/Foundation.h>

import "Person.h"

int main(int argc, const char * argv[]) {

// 内存管理模式
// ARC  自动引用记数
// Automtic Reference Counting
// Mrc  手动引用计数
// Manual Reference Counting
// 管理机制: 引用记数 retainCount

// 控制内存引用记数的方法
// +1
// alloc retain copy
// -1
// release autorelease

/ alloc /

// 0->1 开辟空间   任何一个alloc 对象都为1
Person *p = [[Person alloc] init];
Person *p1 = [[Person alloc] init];
/**     retain   **/
// +1 持有
Person *p2 = [p1 retain];

// [p2 retain];// retain 只是让引用记数+1
// Person *p2 = p1; // p2 只是p1拷贝过来的地址

// 将地址拷贝和引用记数的变化相结合 就是内存管理
// retainCount

// -1
/**     release ***/
//  -1 引用记数 -1
[p release];
NSLog(@"%lu", [p retainCount]);
[p1 release];
[p2 release];

// NSLog(@"%lu", [p retainCount]);

NSLog(@"%lu", [p1 retainCount]);

// NSLog(@"%lu", [p2 retainCount]);

// 创建对象
Person *pp = [[Person alloc] init];
/** copy **/
// +1
// 拷贝之后 pp对象和pp1对象是独立的两段内存空间 相互不影响


Person *pp1 = [pp copy];
NSLog(@"%@ %@", pp1, pp);
NSLog(@"%lu %lu", pp.retainCount, pp1.retainCount);
// 内存管理
[pp release];
[pp1 release];
/** autorelease **/
// 延时 -1 配合autoreleasepool(自动释放)使用
@autoreleasepool {
    Person *per = [[Person alloc] init];// 0 -> 1
    [per retain];// 1 -> 2

// per = nil;// 空对象

    [per release];// 立马减 1  当对象为空时,什么也打印不了
    // 不会立即 -1 在出自动释放池时(延迟) 对每个autorelease -1
    [per autorelease];
    
    NSLog(@"%lu", per.retainCount);
}

/*** 内存管理原则*
 * 当看到alloc/retain/copy时 需要写对应release/autorelease 引用记数加减平衡
 * 看不到 不管
 */
/**
 * 所有权问题
 * 哪个对象对引用计数进行+1 就由哪个对象进行相应的-1
 * 获得所有权->让引用计数+1
 */
Person *dawa = [[Person alloc] init];// 0 -> 1
Person *nanshen = [dawa retain];// 1 -> 2
Person *xiaohua = [dawa retain];// 2 -> 3
Person *marry = dawa;// 3 -> 3 没有所有权
[dawa release];
[nanshen release];
[xiaohua release];

// 遍历构造器
@autoreleasepool {
    // 正常创建对象
    Person *t1 = [[Person alloc]initWithName:@"ss" age:12];
    // 内存管理
    [t1 release];
    // 遍历构造器 不需要在外部管理内存
    Person *t2 = [Person personWithName:@"qq" age:23];
}
 

/**
 * 属性内存管理
 * retain/copy 类型的属性 使用setter方法赋值时 会对赋值的对象引用计数 +1 (让对象对赋值的内容有所有权) 防止提前被释放
 * 举例: p.name = name name会被引用计数 +1
 * retain/copy类型属性 需要在dealloc方法中 让对应的成员变量release
 * 举例: [_name release];
 */

// 字符串的内存管理
// 不可变字符串永远为 -1
NSString *str = @"123";
NSLog(@"~~~%ld", str.retainCount);
// 可变字符串 根正常对象一样
NSMutableArray *mStr = [str mutableCopy];
NSLog(@"!!%ld", mStr.retainCount);

// 容器内存管理
NSMutableArray *mArr = [NSMutableArray array];
Person *ppp = [[Person alloc] init];
// 对象加入collection时 集合会对加入的对象拥有一次所有权 让引用对象 +1
[mArr addObject:ppp];
[mArr addObject:ppp];
// 对象移除时 引用计数 -1
[mArr removeObject:ppp];
// 数组销毁时对数组中所有元素逐一 -1
// [mArr release];
NSLog(@"%lu %lu", ppp.retainCount, mArr.retainCount);





return 0;

}



//
// Test.h
// OC_内存管理
//
// Created by YIem on 15/12/3.
// Copyright (c) 2015年 www.yiem.net YIem博客. All rights reserved.
//

import <Foundation/Foundation.h>

@interface Test : NSObject
@property (nonatomic, copy)
NSString *a;
@property (nonatomic, retain)
NSArray *b;
@property (nonatomic, retain)
NSMutableArray *c;
@property (nonatomic, retain)
NSDictionary *d;
@property (nonatomic, retain)
NSMutableDictionary *e;
@property (nonatomic, assign)
NSMutableDictionary *f ;
@end


//
// Test.m
// OC_内存管理
//
// Created by YIem on 15/12/3.
// Copyright (c) 2015年 www.yiem.net YIem博客. All rights reserved.
//

import "Test.h"

@implementation Test

  • (void)dealloc
    {

    [_a release];
    [_b release];
    [_c release];
    [_d release];
    [_e release];
    [super dealloc];

    }

@end



//
// Person.h
// OC_内存管理
//
// Created by YIem on 15/12/3.
// Copyright (c) 2015年 www.yiem.net YIem博客. All rights reserved.
//

import <Foundation/Foundation.h>

// <NSCopying> 协议 提供一些需要实现的方法声明
@interface Person : NSObject<NSCopying>
@property (nonatomic, copy)
NSString *name;
@property (nonatomic, assign)
NSInteger age;

/// 初始化

  • (instancetype)initWithName:(NSString *)name

                         age:(NSInteger)age;

    // 遍历构造器

  • (instancetype)personWithName:(NSString *)name

                           age:(NSInteger)age;
    

@end


//
// Person.m
// OC_内存管理
//
// Created by YIem on 15/12/3.
// Copyright (c) 2015年 www.yiem.net YIem博客. All rights reserved.
//

import "Person.h"

@implementation Person

// dealloc 方法对应alloc 负责销毁/回收内存
// 一定不要手动对应该方法!!!!
// 当该类的引用记数减为0时 系统自动调用该方法 销毁对象所在堆内存
//

  • (void)dealloc
    {

    // retain/copy类型的属性 要给对应的成员变量release
    [_name release];
    NSLog(@"对象%@被销毁", self);
    [super dealloc];

    }

// 使用copy时 首先签订NSCopying 协议 得到copyWithZone:方法声明 实现方法

  • (id)copyWithZone:(NSZone *)zone
    {
    // 拷贝缓冲池
    Person *p = [[Person allocWithZone:zone] init];
    // 将源内容复制一份
    p.name = self.name;
    p.age = self.age;
    return p;

    }

  • (instancetype)initWithName:(NSString *)name age:(NSInteger)age
    {
    self = [super self];
    if (self) {

    self.name = name;
    self.age = age;

    }
    return self;
    }

  • (instancetype)personWithName:(NSString *)name age:(NSInteger)age
    {
    Person *p = [[Person alloc] initWithName:name age:age];
    // 遍历构造器 使用autorelease 对alloc的引用计数 延时-1
    return [p autorelease];

    }

@end