黑马程序员-OC内存管理

来源:互联网 发布:9.1完美越狱工具mac 编辑:程序博客网 时间:2024/05/20 11:52
------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];}@endBook.h->#import <Foundation/Foundation.h>@interface Book : NSObject@endBook.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
原创粉丝点击