黑马程序员-OC内存管理

1 篇文章 0 订阅
1 篇文章 0 订阅
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
内存管理
    1.移动设备的内存极其有限,每个app所能占用的内存是有限制的
    2.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间,比如回收一些不需要使用的对象、变量等
    3.管理范围:任何继承了NSObject的对象,结其他基本数据类型(int、char、float、double、struct、enum等)无效


引用计数器
    1.每个oc对象都有4个字节的空间用来存储引用计数器
    2.每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象

引用计数器的作用
    1.当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
    2.当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出。

引用计数器的操作
    1.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
    2.给对象发送一条release消息,可以使引用计数器值-1
    3.可以给对象发送retainCount消息获得当前的引用计数器值

对象的销毁
    1.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
    2.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
    3.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
    4.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
    5.不要直接调用dealloc方法
    6.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(即指针错误)

Xcode6找不到Use Automatic Reference Counting

手动关闭arc
    新建项目完成后,点击左侧栏里的第一行,标题
    这时主界面就会出现很多设置的项目。在上方有一个搜索栏。输入language或者ARC。
    在搜索条件将Basic改为All,Combined改为Levels
    然后找到Objective-C Automatic Reference Counting 设置为no
    就可以使用release等代码了

野指针,指向已回收的对象(不可用内存地址)的指针
        //EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)

打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects

内存管理原则
1.原则分析
    房间原理,只要房间还有人在用,就不会解散
    只要还有人在用某个对象,那么这个对象就不会回收
    只要你想用这个对象,就让对象的计数器+1
    当你不再使用这个对象时,就让对象的计数器-1
    当你换房间时,原来房间的对象计数器-1,新房间+1

2.原则规范
    如果通过alloc、new或[mutable]copy来创建一个对象,那么必须调用release或 autorelease,不用自己创建的不用管


内存管理代码规范
 1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release
 2.set方法的代码规范
 1>基本数据类型:直接复制,无需内存管理
 2>oc对象类型
 - (void)setCar:(Car *)car
 {
    //1.他判断是不是新传进来对象
    if(car!=_car)
    {
        //2.对旧对象做一次release
        [_car release];
        //3.对新对象做一次retain
        _car = [car retain];
    }
 }
 3.dealloc方法的代码规范
 1>一定要[super dealloc],而且放到最后面
 2>对self(当前)所拥有的其他对象做一次release
 -(void)dealloc
 {
    [_car release];
    [super dealloc];
 }


如果调用了retain,无论这个对象是如何生成的,都需要调用release.

property
    1.set方法内存管理相关的参数
        retain:release旧值 ,retain新值(适用于OC对象类型)
        assing:直接赋值(默认,适用于非OC对象类型)
        copy:release旧值,copy新值(一般用于NSString)
    
    2.是否要生成set方法
        readwrite:同时生成setter和getter的声明、实现
        readonly:只会生成getter的声明、实现
    
    3.多线程管理
        nonatomic:不加线程锁,性能高(ios一般就用这个)
        atomic:加线程锁,性能低(默认)
    
    4.setter和getter方法的名称
        setter : 决定了set方法的名称,一定要有个冒号
        getter : 决定了get方法的名称(一般用在BOOL类型的get方法,一般以is开头)
        
    5.@property(getter = getWeight) int weight;
    6.setHeight,height 同时生成setter和getter的声明、实现
    7.@property (readwrite,assign) int height;
    //不加锁性能高,直接赋值 age
    8.@property (nonatomic,assign) int age;
    //内存管理的name
    9.@property (retain) NSString *name;
    
循环引用

    当互相引用的时候,使用#import"类.h",类文件将会互相拷贝.
    //而且为了提高编译效率,在头文件里并不需要类的全部内容,所以使用@class就足够了。
    
    1.@class的作用:仅仅告诉编译器,某个名称是一个类
        @class Person;//仅仅告诉编译器,Person是一个类
    
    2.开发中引用一个类的规范
        1>在.h文件中用@class来声明类
        2>在.m文件中用#import来包含类的所有东西
    
    3.@class和#import的区别
        1> #import方式会包含类的所有信息,包括被引用类的变量和方法;
        2> @class方式只是告诉编译器在A.h文件中B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中的信息
        3>如果有上面个头文件都#import了同一个文件,或者这些文件依次被#import那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了
        4>在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
    
    3.循环retain
        1>比如A对象retain了B对象,B对象retain了A对象
        2>这样会导致A对象和B对象永远无法释放
    
        解决方案
        当两端互相引用时,应该一端用retain,一端用assign
    
    retain:release旧值 ,retain新值(适用于OC对象类型)
    assing:直接赋值(默认,适用于非OC对象类型)
    
autorelease的基本用法

1.autorelease的基本用法
    1>会将对象放到一个自动释放池中
    2>当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
    3>会返回对象本身
    4>调用完autorelease方法后,对象的计数器不变

2.autorelease的好处
    1>不用再关心对象释放的时间
    2>不用再关心什么时候调用release

3.autorelease的使用注意
    1>占用内存较大的对象不要随便使用autorelease
    2>占用内存较小的时象使用autorelease,没有太大影响

4.自动释放池
    1>在ios程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
    2>当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池

5.关于系统类
    1>系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
    比如不需要的NSString * str = [NSString stringWithFormatL@"age is %d",10];
    比如需要的  NSNumber *num = [[NSNumber alloc]initWithInt:10];
       [num release]
    2>系统规范,方法名以类名开头。
    3>OC不允许类同名,不像java可以用包来区别或c#的命名空间。
    4>开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象。

    6.关于子类
        1>如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
        2>创建对象时,不要直接用类名,一般用self
        例+ (id)person
        {
            return [[ss[self alloc]init] autorelease];
        }
        
ARC
    将非arc代码重构成arc代码:
    Edit->
    Refactor->Convert to Objective-C ARC ->next->save
    
    使用第三方框架,可能不是arc的,就需要项目中,即需要arc,又可以不用arc
    配置个别类,不使用arc:Xcode->s项目配置页,第一个页->Build Phases-类文件-回车或双击,弹出一个对话框,在对话框中输入-fno-bojc-arc
    -fno-bojc-arc 不支持arc
    -f-bojc-arc   支持arc
    
    ARC判断准则:只要没有强指针指向对象,就会释放对象
    ARC特点
        1>不允许调用release、retain、retainCount
        2>允许重写dealloc,但是不允许调用[super dealloc]
        3>@property的参数
            * strong : 成员变量是强指针(适用于OC对象类型)
            * weak   : 成员变量是弱指针(适用于OC对象类型)
            * assign : 适用于非OC对象类型
        4>使用ARC后,以前的retain改为strong其它一切不变
    
    指针分2种:
    1>强指针:默认情况下,所有的指针都是强针 __Strong
    2>弱指针:只要没有强指针指向对象,对象被清空,如果对象被清空,弱指针被清空__weak
    
    当指针p=nil时,对象没有指针指向而被释放
    相当于,在检测到对象没有指针指向时,被[p release]
    
    __strong Person *p = nil;
    __weak Person *p = nil;
    
    @property (nonatomic,strong) Dog *dog;
    @property (nonatomic,weak) Dog *dog;
    ARC机制下的,写法类似java
    
    当两端循环引用的时候,解决方案:
    1>ARC
        1端用strong,另1端用weak
    2>非ARC

        1端用retain,另1端用assign

Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject

@end

Person.m->

#import "Person.h"

@implementation Person
//当一个Person对象被回收时自动调用这个方法
- (void)dealloc
{
    
    NSDate *currDate=[NSDate date];//先获取当前时间
    //以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式
    NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init];
    [dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
    //利用上面的时间格式工具把日期转换成字符串对象格式
    NSString *dateStr=[dateFormate stringFromDate:currDate];
    
    NSLog(@"Person 回收了 time:%@",dateStr);
    
    //一定要调用父类的回收方法,而且要放在最后面
    [super dealloc];
}
+ (void)load
{
    NSDate *currDate=[NSDate date];//先获取当前时间
    //以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式
    NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init];
    [dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
    //利用上面的时间格式工具把日期转换成字符串对象格式
    NSString *dateStr=[dateFormate stringFromDate:currDate];
    
    NSLog(@"Person load time:%@",dateStr);
}
@end



main.m->

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        //调用引用计数器 alloc计数器加1
        Person *p = [[Person alloc]init];
        //类型不匹配需要强转int a = (int),或是使用匹配类型NSInteger
        int a = (int)[p retainCount];
        NSInteger b =[p retainCount];
        NSLog(@"p retainCount 1:%d,%ld",a,b);
        
        //发送release引用计数器减一,减为零时,对象回收
        //验证对象是否回收,重写-dealloc
       // [p release];
        //给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
        //当对象被回收时,再发送retain就不对了。
        //retain计数器加1,返回对象本身
        [p retain];
        b =[p retainCount];
        NSLog(@"p retainCount 2:%d,%ld",a,b);
        [p release];
        [p release];
        //已回收后多次回收同样报错
        //野指针,指向已回收的对象(不可用内存地址)的指针
        //EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)
        //[p release];
        b =[p retainCount];
        NSLog(@"p retainCount 3:%d,%ld",a,b);
        //避免野指针的方法
        //变成空指针,空指针指向nil,null,0
        p = nil;
        b =[p retainCount];
        NSLog(@"p retainCount 4:%d,%ld",a,b);
        
        //当p = nil;后 [p release]就不报错了,因为指针没有指向作何内存
        //无效信息,oc没有空指针错误,给空指针发送消息不报错,仅仅是无效警告
        [p release];
        //打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects
        
        //打开僵尸对象检测开关后
        // -[Person setAge:]:message sent to deallocated instance 0x100109a10
        //给已经释放的对象发送了一条-setAge:消息;
        //p.age=10;
    }
    return 0;
}



控制台:
2014-11-09 19:44:55.468 01引用计数器[869:303] Person load time:2014/11/09 19:44:55:461
2014-11-09 19:44:55.468 01引用计数器[869:303] Hello, World!
2014-11-09 19:44:55.469 01引用计数器[869:303] p retainCount 1:1,1
2014-11-09 19:44:55.470 01引用计数器[869:303] p retainCount 2:1,2
2014-11-09 19:44:55.471 01引用计数器[869:303] Person 回收了 time:2014/11/09 19:44:55:471
2014-11-09 19:44:55.471 01引用计数器[869:303] p retainCount 3:1,1
2014-11-09 19:44:55.472 01引用计数器[869:303] p retainCount 4:1,0


Person.h->

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

@interface Person : NSObject
{
    //当Book是成员变量时,Book无法继承Person
    Book *_book;
}

- (void)setBook:(Book *)book;
- (Book *)book;
@end



Person.m->

#import "Person.h"
#import "Book.h"

@implementation Person
- (void)setBook:(Book *)book
{
    //如果_book没有值,就直接retain如果有值,则将原先的release
    //可以不加判断直接 release因为oc中空指针发消息不报错
    if(_book!=nil){
        [_book release];
    }
    _book = [book retain];
}
- (Book *)book
{
    return _book;
}
- (void)dealloc
{
    //对象回收前将所持有的资源处理
    [_book release];
    
    NSLog(@"Person dealloc");
    [super dealloc];
}
@end




Book.h->

#import <Foundation/Foundation.h>

@interface Book : NSObject

@end



Book.m->

#import "Book.h"

@implementation Book
- (void)dealloc
{
    
    NSLog(@"Book dealloc");
    [super dealloc];
}
@end



main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Book.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        //p计数器加1
        Person *p = [[Person alloc]init];
        
         //b,b2计数器加1
        Book *b = [[Book alloc]init];
        Book *b2 = [[Book alloc]init];
        
        NSInteger i = [p retainCount];
        NSLog(@"p retainCount:%ld",i);
        
        //p调用b b计数器+1
        p.book = b;
        
        i = [b retainCount];
        NSLog(@"b retainCount:%ld",i);
        
        //p调用b2,b-1 ,b2+1
        p.book = b2;
        
        i = [b retainCount];
        
        NSInteger i2 = [b2 retainCount];
        NSLog(@"b:%ld,b2 retainCount:%ld",i,i2);
        
        [b release];
        b = nil;
        
        [b2 release];
        b2 = nil;
        
        //计数器减1
        [p release];
        p=nil;
    }
    return 0;
}




控制台:
2014-11-09 23:15:57.816 02多对象内存管理[1401:303] Hello, World!
2014-11-09 23:15:57.819 02多对象内存管理[1401:303] p retainCount:1
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b retainCount:2
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b:1,b2 retainCount:2
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.822 02多对象内存管理[1401:303] Person dealloc


Person.h->

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

@interface Person : NSObject
{
    int _age;
    Car * _car;
}
- (void)setAge:(int)age;
- (int)age;

- (void)setCar:(Car *)car;
- (Car *)car;
@end




Person.m->


#import "Person.h"

@implementation Person

- (void)setAge:(int)age
{
    //基础数据类型不需要管理内存
    _age = age;
}
- (int)age
{
    return _age;
}

- (void)setCar:(Car *)car
{
    //因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效
    //p.car = c1;
    //解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作
    
    if(_car!=car){
    
        //因为oc空指针发消息不报错,所以不用判断,直接发回收信息
        [_car release];
        //将新车赋给人
        _car = [car retain];
    
    }
}
- (Car *)car
{
    return _car;
}
- (void)dealloc
{
    //回收所拥有的车
    [_car release];
    NSLog(@"age:%d of Person dealloc",_age);
    [super dealloc];
}
@end



Car.h->

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    int _speed;
}
- (void)setSpeed:(int)speed;
- (int)speed;
@end



Car.m->
#import "Car.h"

@implementation Car

- (void)setSpeed:(int)speed
{
    //基础数据类型不需要管理内存
    _speed = speed;
}
- (int)speed
{
    return _speed;
}
- (void)dealloc
{

    NSLog(@"speed:%d of Car dealloc",_speed);
    [super dealloc];
}
@end



main.m->

//
//  main.m
//  03set方法内存管理
//
//  Created by Whome on 14-11-9.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Car.h"
/*
 内存管理代码规范
 1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release
 2.set方法的代码规范
 1>基本数据类型:直接复制,无需内存管理
 2>oc对象类型
 - (void)setCar:(Car *)car
 {
    //1.他判断是不是新传进来对象
    if(car!=_car)
    {
        //2.对旧对象做一次release
        [_car release];
        //3.对新对象做一次retain
        _car = [car retain];
    }
 }
 3.dealloc方法的代码规范
 1>一定要[super dealloc],而且放到最后面
 2>对self(当前)所拥有的其他对象做一次release
 -(void)dealloc
 {
    [_car release];
    [super dealloc];
 }
 */
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        //年龄为20的人 p-1
        Person *p = [[Person alloc]init];
        p.age =20;
        //速度为70的车 c-1
        Car *c = [[Car alloc]init];
        c.speed = 70;
        //速度为100的车 c1-1
        Car *c1 = [[Car alloc]init];
        c1.speed = 100;
        //年龄20的人有了速度70的人 c-2
        p.car = c;
        //年龄20的人有了速度100的人 c-1 c1-2
        p.car = c1;
        
        //一个不严谨的写法
        // c1-1
        //[c1 release];
        
        //因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效
        //p.car = c1;
        
        //解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作
        
        [p release];
        
        [c release];
        
        [c1 release];
        
    }
    return 0;
}



控制台:

2014-11-10 06:12:56.265 03set方法内存管理[458:303] Hello, World!
2014-11-10 06:12:56.269 03set方法内存管理[458:303] age:20 of Person dealloc
2014-11-10 06:12:56.270 03set方法内存管理[458:303] speed:70 of Car dealloc
2014-11-10 06:12:56.271 03set方法内存管理[458:303] speed:100 of Car dealloc


Person.h->

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

/*
 1.set方法内存管理相关的参数
 retain:release旧值 ,retain新值(适用于OC
 对象类型)
 assing:直接赋值(默认,适用于非OC对象类型
 )
 copy:release旧值,copy新值
 
 2.是否要生成set方法
 readwrite:同时生成setter和getter的声明、实
 现
 readonly:只会生成getter的声明、实现
 
 3.多线程管理
 nonatomic:不加线程锁,性能高(ios一般就用这
 个)
 atomic:加线程锁,性能低(默认)
 
 4.setter和getter方法的名称
 setter : 决定了set方法的名称,一定要有个冒
 号
 getter : 决定了get方法的名称(一般用在BOOL
 类型的get方法,一般以is开头)
 
 */

@interface Person : NSObject

//(retain):相当于会在set方法中release旧值,retain新值
//缺点dealloc还是需要手写
@property(retain)Book *book;
//返回BOOL类型的方法一般以is开头
@property (getter=isRich) BOOL rich;
//getter名为getW,setter名为setW
@property(getter = ss,setter = qwerq:) int weight;
//setHeight,height 同时生成setter和getter的声明、实现
@property (readwrite,assign) int height;
//不加锁性能高,直接赋值 age
@property (nonatomic,assign) int age;
//内存管理的name
@property (retain) NSString *name;

@end




Person.m->


#import "Person.h"

@implementation Person
/*
 @property(retain)Book *book;
 等同于
 - (void)setBook:(Book *)book
 {
    if(_book!=book){
 
        [_book release];
        _book = [book retain];
 
    }
 }
 - (Book *)book
 {
    return _book;
 }
 */
- (void)dealloc
{
    //回收所拥有的书
    [_book release];
    NSLog(@"Person dealloc");
    [super dealloc];
}
@end

Book.h->

#import <Foundation/Foundation.h>

@interface Book : NSObject

@end


Book.m->

#import "Book.h"

@implementation Book

- (void)dealloc
{

    NSLog(@"Book dealloc");
    [super dealloc];
}
@end




main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Book.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Person *p = [[Person alloc]init];
        Book *b = [[Book alloc]init];
        
        p.book = b;
        NSInteger i = [b retainCount];
        //p.qwerq不好使
        [p qwerq:100];
        p.age = 0;
        p.rich = 1;
        NSLog(@"age:%d,rich=%d weight:%d i:%ld",p.age,p.isRich,p.ss,i);
        [p release];
        p = nil;
        [b release];
        b = nil;
    }
    return 0;
}

控制台:

2014-11-10 08:22:26.994 04set方法_property[708:303] Hello, World!
2014-11-10 08:22:27.000 04set方法_property[708:303] age:0,rich=1 weight:100 i:2
2014-11-10 08:22:27.001 04set方法_property[708:303] Person dealloc
2014-11-10 08:22:27.003 04set方法_property[708:303] Book dealloc


Person.h->

#import <Foundation/Foundation.h>

//仅标明Card是一个类
@class Card;
@interface Person : NSObject

//retain:release旧值 ,retain新值(适用于OC对象类型)
@property (nonatomic,retain) Card *card;

@end

Person.m->


#import "Person.h"
#import "Card.h"

@implementation Person

+ (void)initialize
{
    NSLog(@"initalize Person");
}

+ (void)load
{
    NSLog(@"load Person");
}

- (void)dealloc
{
    
    [_card release];
    
    NSLog(@"dealloc Person");
    
    [super dealloc];
}

@end

Card.h->

#import <Foundation/Foundation.h>

//仅标明Person是一个类
@class Person;
@interface Card : NSObject

//assing:直接赋值(默认,适用于非OC对象类型)
@property (nonatomic,assign) Person *person;

@end


Card.m->

#import "Card.h"
#import "Person.h"

@implementation Card

+ (void)initialize
{
    NSLog(@"initalize Card");
}

+ (void)load
{
    NSLog(@"load Card");
}

- (void)dealloc
{
    
    [_person release];
    
    NSLog(@"dealloc Card");
    
    [super dealloc];
}
@end



main.m->


#import <Foundation/Foundation.h>
#import "Person.h"
#import "Card.h"


/*
 
 循环retain
 1>比如A对象retain了B对象,B对象retain了A对象
 2>这样会导致A对象和B对象永远无法释放
 
 解决方案
 当两端互相引用时,应该一端用retain,一端用assign
 
 */

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        //p-1
        Person *p = [[Person alloc]init];
        //c-1
        Card *c = [[Card alloc]init];
        //c-2
        p.card = c;
        //p-1
        c.person = p;
        
        //c-1
        [c release];
        
        //p-0 c-0
        
        [p release];
    }
    return 0;
}



控制台:

2014-11-11 04:07:22.155 05循环引用[388:303] load Person
2014-11-11 04:07:22.159 05循环引用[388:303] load Card
2014-11-11 04:07:22.159 05循环引用[388:303] Hello, World!
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Person
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Person


Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,assign) int age;

//简化类初始化写法
+ (id)person;
//初始化并给成员变量赋值
+ (id)personWithAge:(int)age;
@end



Person.m->

#import "Person.h"

@implementation Person
- (void)dealloc
{
    NSLog(@"age:%d Person dealloc",_age);
    [super dealloc];
}
//简化类初始化写法
+ (id)person
{
    //如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
    return [[[self alloc]init]autorelease];
}
//初始化并给成员变量赋值
+ (id)personWithAge:(int)age
{
    Person *p = [self person];
    p.age = age;
    return p;
}
@end



GoodPerson.h->

#import "Person.h"

@interface GoodPerson : Person
@property (nonatomic,assign) int money;
@end


GoodPerson.m->

#import "GoodPerson.h"

@implementation GoodPerson
- (void)dealloc
{
    NSLog(@"money:%d GoodPerson dealloc",_money);
    [super dealloc];
}
@end



main.m->


#import <Foundation/Foundation.h>
#import "Person.h"
#import "GoodPerson.h"

/*
 autorelease方法会返回对象本身
 调用完autorelease方法后,对象的计数器不变
 autorelease会将对象放到一个自动释放池中
 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
 */
int main(int argc, const char * argv[]) {
   
    
    
    //一个内存栈,一般存放占用内存较小的对象
    //声明这个代码块是一个自动释放池,当自动释放池销毁时,autorelease的对象将被release
    @autoreleasepool
    {//{开始代表创建了释放池
        Person *p1 = [[[Person alloc]init]autorelease];
        p1.age = 20;
    }//}结束代表销毁释放池
    
    
    //自动释放池的其它写法
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    Person *pp = [[[Person alloc]init]autorelease];
    pp.age = 100;
    [pool release];
    
    
    //将池子清空
    //[pool drain];
    
    //简化类初始化写法,初始化成员变量,栈先进后出
    @autoreleasepool {
        Person *pw = [Person person];
        pw.age = 101;
        
        Person *pw1 = [Person personWithAge:102];
    }
    
    
    //常用错误
    //1.没有放在@autoreleasepool{}中是无法调用release的
    Person *p2 = [[[Person alloc]init]autorelease];
    p2.age = 10;
    
    //2.发送了两次autorelease,当池销毁时,也会发送两次release,但是在上一次的时候,已经变成野指针了,所以无效
//    @autoreleasepool
//    {
//        Person *p3 = [[[[Person alloc]init]autorelease] autorelease];
//    }
    
    //2.当p4发送release后,p4已经成为野指针了,而当池子销毁时,会再一次发送release所以无效。
//    @autoreleasepool
//    {
//        Person *p4 = [[[Person alloc]init]autorelease];
//        
//        [p4 release];
//    }
    
    
    //关于子类细节
    @autoreleasepool {
        
        //如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
        GoodPerson *gp = [GoodPerson personWithAge:103];
        // '-[Person setMoney:]: unrecognized selector sent to instance 0x100603970'
        gp.money = 10;
    }
    

 
    return 0;
}



控制台:

2014-11-11 08:37:58.637 06-autorelease[565:303] age:20 Person dealloc
2014-11-11 08:37:58.639 06-autorelease[565:303] age:100 Person dealloc
2014-11-11 08:37:58.640 06-autorelease[565:303] age:102 Person dealloc
2014-11-11 08:37:58.641 06-autorelease[565:303] age:101 Person dealloc
2014-11-11 08:37:58.642 06-autorelease[565:303] money:10 GoodPerson dealloc
2014-11-11 08:37:58.643 06-autorelease[565:303] age:103 Person dealloc
Program ended with exit code: 0


Person.h->

#import <Foundation/Foundation.h>

@class Dog;

@interface Person : NSObject

//强指针
@property (nonatomic,strong) Dog *dog;

@end




Person.m->

#import "Person.h"

@implementation Person

- (void)dealloc
{
    NSLog(@"Person dealloc");
    //ARC不允许,调用父类的dealloc
    //[super dealloc];
}


@end

Dog.h->

#import <Foundation/Foundation.h>

@class Person;

@interface Dog : NSObject

//强指针
@property (nonatomic,strong) Person *person;

@end




Dog.m->

#import "Dog.h"

@implementation Dog

- (void)dealloc
{
    NSLog(@"Dog dealloc");
}

@end

main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
/*
 
 ARC判断准则:只要没有强指针指向对象,就会释放对象
 
 ARC特点
 1>不允许调用release、retain、retainCount
 2>允许重写dealloc,但是不允许调用[super dealloc]
 3>@property的参数
 * strong : 成员变量是强指针(适用于OC对象类型)
 * weak   : 成员变量是弱指针(适用于OC对象类型)
 * assign : 适用于非OC对象类型
 4>使用ARC后,以前的retain改为strong其它一 切不变

 
 指针分2种:
 1>强指针:默认情况下,所有的指针都是强针 __Strong
 2>弱指针:只要没有强指针指向对象,对象被清空 ,如果对象被清空,弱指针被清空__weak
 
 当指针p=nil时,对象没有指针指向而被释放相当于,在检测到对象没有指针指向时,被[p release]
 
 __strong Person *p = nil;
 
 __weak Person *p = nil;
 
 ARC机制下的,写法类似java

 */

int main(int argc, const char * argv[]) {
    
    //强指针,默认强指针
    __strong Person *p = [[Person alloc]init];
    NSLog(@"p:%@",p);
    
    //弱指针
    __weak Person *p2 =p;
    
    NSLog(@"p2-1:%@",p2);
    
    p = nil;
    p2 = nil;
    
    //错误写法,因为没有强指针指向类对象,类对象不会存在,类对象不存在,指向类对象的弱指针也会被清空
    p2 = [[Person alloc]init];
    
    NSLog(@"p2-2:%@",p2);

    p = [[Person alloc]init];
    
    Dog *d = [[Dog alloc]init];
    
    p.dog = d;
    
    NSLog(@"p.dog-1:%@",p.dog);
    
    d = nil;
    
    p.dog = d;
    
    NSLog(@"p.dog-2:%@",p.dog);
    
    //arc的循环引用
    //因为都是强指针,所以会导至无法释放,解决办法,将其中d.person变为弱指针,即人不存在了,指针无聊。
    p = [[Person alloc]init];
    d = [[Dog alloc]init];
    
    p.dog = d;
    d.person = p;
    
    /*
     当main结束时首先销毁d,然后销毁p,然后人和狗的类还存在,它们互相强指针,所以都没释放,但是如果将其中一个弱指针,那么被弱指针指向的类对象,就可以被销毁,它的强指针成员也就不存在,那么那个拥有弱指针成员的类对象也就被销毁
     */

    
    return 0;
}




控制台:
2014-11-11 23:20:01.803 07ARC[627:303] p:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] p2-1:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] p2-2:(null)
2014-11-11 23:20:01.807 07ARC[627:303] p.dog-1:<Dog: 0x1001042f0>
2014-11-11 23:20:01.807 07ARC[627:303] Dog dealloc
2014-11-11 23:20:01.808 07ARC[627:303] p.dog-2:(null)
2014-11-11 23:20:01.809 07ARC[627:303] Person dealloc
Program ended with exit code: 0


       
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值