OC基础-内存管理(二)MyArray解释addObject原理

一、看MutableArray中的addObject之后的retainCount

Dog.h

#import <Foundation/Foundation.h>

@interface Dog : NSObject
{
    int _ID;
}

@property (assign) int ID;

@end
Dog.m

#import "Dog.h"

@implementation Dog

@synthesize ID = _ID;

//重写该方法,该方法自动会调用
-(void)dealloc{
    NSLog(@"dog id %d is dealloc", _ID);
    [super dealloc];
}
@end

main.m

#import <Foundation/Foundation.h>
#import "Dog.h"

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

        NSMutableArray * array = [[NSMutableArray alloc] init];
        for(int x = 0; x <5; x++){
            Dog * d = [[Dog alloc] init];
            [d setID: x];
            NSLog(@"dog retainCount is %ld", [d retainCount]);
            [array addObject:d];
            NSLog(@"dog retainCount2 is %ld", [d retainCount]);
            [d release];
        }
        
        [array release];
    }
    return 0;
}
输出结果:

2015-10-02 19:11:18.605 内存管理-MyArray[1770:59076] dog retainCount is 1
2015-10-02 19:11:18.606 内存管理-MyArray[1770:59076] dog retainCount2 is 2
2015-10-02 19:11:18.606 内存管理-MyArray[1770:59076] dog retainCount is 1
2015-10-02 19:11:18.606 内存管理-MyArray[1770:59076] dog retainCount2 is 2
2015-10-02 19:11:18.607 内存管理-MyArray[1770:59076] dog retainCount is 1
2015-10-02 19:11:18.607 内存管理-MyArray[1770:59076] dog retainCount2 is 2
2015-10-02 19:11:18.607 内存管理-MyArray[1770:59076] dog retainCount is 1
2015-10-02 19:11:18.607 内存管理-MyArray[1770:59076] dog retainCount2 is 2
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog retainCount is 1
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog retainCount2 is 2
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog id 0 is dealloc
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog id 1 is dealloc
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog id 2 is dealloc
2015-10-02 19:11:18.608 内存管理-MyArray[1770:59076] dog id 3 is dealloc
2015-10-02 19:11:18.609 内存管理-MyArray[1770:59076] dog id 4 is dealloc
Program ended with exit code: 0
分析:

for循环四次,每次都进行相同的操作,目的是在数组中添加一个dog对象。

每次创建一个dog对象,retainCount=1,对象被引用次数为1,也就是自身保留,不被释放;

然后使用addObject方法,将对象添加到数组中,该对象的引用次数为2,除了自身之外,还被数组保留;

然后[d release],使得retainCount=1, 自身保留引用被删除,该对象只被数组拥有。

[array release],先释放数组中的dog对象,数组然后才被释放。


二、使用自定义数组分析addObject函数到底进行了操作

在上面的例子中,调用addObject方法后,retainCount就会+1,那其中到底进行了什么操作呢?

下面自己创建一个简单的数组类,来模拟其中的操作

MyArray.h

#import <Foundation/Foundation.h>
//创建一个简易版的数组来分析addObject内部的操作。
@interface MyArray : NSObject
{

    NSUInteger _count;   //数组元素个数
    id _objs[512];      //创建一个512个元素的数组,大小4x512字节
}
@property (assign, readonly)NSUInteger count;

-(void)addObject: (id)object;
-(id)objectAtIndex: (NSUInteger)index;
-(void)removeObjectAtIndex: (NSUInteger)index;
-(void)removeAll;

@end
MyArray.m

#import "MyArray.h"

@implementation MyArray

@synthesize count = _count;

-(id) init{
    self = [super init];
    if(self){
        _count = 0;
    }
    return self;
}

-(void)addObject:(id)object{
    if(_count > 512){
        return;
    }
    _objs[_count] = [object retain];
    _count++;
    //这里必须retain一次。因为如果外部调用了该方法,然后又调用了release,那么这里存的就是一个野指针。
}
-(id)objectAtIndex:(NSUInteger)index{
    return _objs[index];
}
-(void)removeObjectAtIndex:(NSUInteger)index{
    id obj = _objs[index];
    [obj release];
    //因为添加元素的时候有retain一次,这里必须release
    _objs[index] = nil;
}
-(void)removeAll{
    for(int i = 0; i<_count; i++){
        [self removeObjectAtIndex: i];
    }
}

-(void)dealloc{
    NSLog(@"before remove all");
    [self removeAll];
    NSLog(@"after remove all");
    
    [super dealloc];
}
@end
main.m

#import <Foundation/Foundation.h>
#import "Dog.h"
#import "MyArray.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
#if 0
        NSMutableArray * array = [[NSMutableArray alloc] init];
        for(int x = 0; x <5; x++){
            Dog * d = [[Dog alloc] init];
            [d setID: x];
            NSLog(@"dog retainCount is %ld", [d retainCount]);
            [array addObject:d];
            NSLog(@"dog retainCount2 is %ld", [d retainCount]);
            [d release];
        }
        [array release];
#endif
        
        MyArray * array = [[MyArray alloc] init];
        for(int x = 0 ; x< 5; x++){
            Dog * d = [[Dog alloc] init];
            [d setID:x];
            NSLog(@"dog retainCount is %ld", [d retainCount]);
            [array addObject:d];
            NSLog(@"dog retainCount2 is %ld", [d retainCount]);
            [d release];
        }
        [array release];
    }
    return 0;
}

对比自定义数组的代码和OC提供的数组代码,操作很相似。

查看输出结果:

2015-10-02 19:43:03.291 内存管理-MyArray[2297:69892] dog retainCount is 1
2015-10-02 19:43:03.293 内存管理-MyArray[2297:69892] dog retainCount2 is 2
2015-10-02 19:43:03.293 内存管理-MyArray[2297:69892] dog retainCount is 1
2015-10-02 19:43:03.293 内存管理-MyArray[2297:69892] dog retainCount2 is 2
2015-10-02 19:43:03.293 内存管理-MyArray[2297:69892] dog retainCount is 1
2015-10-02 19:43:03.293 内存管理-MyArray[2297:69892] dog retainCount2 is 2
2015-10-02 19:43:03.294 内存管理-MyArray[2297:69892] dog retainCount is 1
2015-10-02 19:43:03.294 内存管理-MyArray[2297:69892] dog retainCount2 is 2
2015-10-02 19:43:03.294 内存管理-MyArray[2297:69892] dog retainCount is 1
2015-10-02 19:43:03.294 内存管理-MyArray[2297:69892] dog retainCount2 is 2
2015-10-02 19:43:03.295 内存管理-MyArray[2297:69892] before remove all
2015-10-02 19:43:03.295 内存管理-MyArray[2297:69892] dog id 0 is dealloc
2015-10-02 19:43:03.295 内存管理-MyArray[2297:69892] dog id 1 is dealloc
2015-10-02 19:43:03.295 内存管理-MyArray[2297:69892] dog id 2 is dealloc
2015-10-02 19:43:03.295 内存管理-MyArray[2297:69892] dog id 3 is dealloc
2015-10-02 19:43:03.296 内存管理-MyArray[2297:69892] dog id 4 is dealloc
2015-10-02 19:43:03.296 内存管理-MyArray[2297:69892] after remove all
Program ended with exit code: 0

从上面可以看出输出结果和之前的是一样的,也就是说在addObject函数内部实际上是进行了retain操作,而在removeObject函数中相应的进行了release操作,每一个release对应一个retain,严格遵守黄金法则。


@诗未冷学习博客

你可能感兴趣的:(oc,黄金法则,OC内存管理,retain和release)