黑马程序员---IOS内存管理

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


一.概述

  每个对象在初始化的时候都会被分配一块内存。就像图书馆一样,每个人只借书却不还书,图书馆会因为无书可借而倒闭。然而内存也是一样,每个对象都分配一块内存,如果内存不释放的话,将会耗尽内存资源。可是怎么才能知道这块内存已经不需要使用了呢?OC有个引用计数,每个分配内存的对象都有一个相关联的整数,叫做引用计数器。当这个对象需要被访问的时候这个对象的计数器就加一,当结束访问这个对象时计数器就减一。当计数器为0的时候就销毁这个对象。

二.内存管理范围

  任何继承NSObject的对象分配的内存都需要被管理,以免造成内存的泄漏。

三.内存的管理原理

  1.当使用alloc,new,copy等消息创建一个对象时,这个对象的引用计数会为一。

  2.给对象发送retain消息可以使得这个对象的引用计数加一。

  3.给对象发送release消息可以使得这个对象的引用计数减一。

  4.当这个对象的引用计数为0的时候就会发送dealloc消息销毁对象掉释放这块内存。

  5.可以给对象发送retainCount消息查询这个对象的引用计数.

四.内存管理原则

  1.谁创建这个对象,就负责释放这个对象。

  2.谁调用了retain方法,就应该调用release方法.


代码如下


#import <Foundation/Foundation.h>
//电池类头文件
@interface Battery : NSObject

@end

//电池类实现
#import "Battery.h"

@implementation Battery
- (NSString *) description
{
    return @"I'm a battery";
}

//重写dealloc方法
- (void)dealloc
{
    //打印
    NSLog(@"battery byebye");
    //调用父类dealloc方法
    [super dealloc];
}
@end

//main.m
#import <Foundation/Foundation.h>
#import "Battery.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        // 通过发送new消息创建battery对象,引用计数为1
        Battery *battery = [Battery new];
 
        // 发送retain消息,引用计数加一为2
        [battery retain];
        
        // 通过发送retaincount消息查看引用计数并打印
        NSLog(@"%zi", [battery retainCount]);
        
        // 发送release消息,引用计数减一为1
        [battery release];
        
        // 通过发送retaincount消息查看引用计数并打印
        NSLog(@"%zi", [battery retainCount]);
        
        // 发送release消息,引用计数减一为0 发送dealloc消息
        [battery release];
        
        // 此时的battery已经被销毁了 却访问这块内存 会发生野指针错误	
        NSLog(@"%zi", [battery retainCount]);

        
        
    }
    return 0;
}



五.set方法内存管理

  1.谁创建这个对象,谁就负责释放这个对象。手机里面需要安装一块电池,当声明了一个电池对象并把它set进手机中,这个电池就应该被release释放掉。当需要手机发送一条消息需要看到这个电池的牌子,这个时候就会报错了,因为电池的那块内存已经被释放掉了,应该怎么解决这个问题呢?

代码如下所示:

//
//  Battery.h
//  内存管理
//
//  Created by AndyJerry on 14-12-9.
//  Copyright (c) 2014年 AndyJerry. All rights reserved.
//

#import <Foundation/Foundation.h>
//电池类头文件
@interface Battery : NSObject
{
    //电池品牌
    NSString *_brand;
}
- (NSString *) brand;

- (void) setBrand:(NSString *)brand;
@end


//电池类实现
#import "Battery.h"

@implementation Battery

-(NSString *)brand
{
    return _brand;
}

-(void)setBrand:(NSString *)brand
{
        _brand = brand;
}
- (NSString *) description
{
    return @"I'm a battery";
}

//重写dealloc方法
- (void)dealloc
{
    //打印
    NSLog(@"%@battery被销毁",_brand);
    //调用父类dealloc方法
    [super dealloc];
}
@end

#import <Foundation/Foundation.h>
//@class Battery;
#import "Battery.h"
@interface Iphone : NSObject
{
    Battery * _battery;
    
    NSString *_brand;
}

-(void) setBattery:(Battery *)battery;

-(Battery *) battery;

- (NSString *) brand;

- (void) setBrand:(NSString *)brand;
@end

#import "Iphone.h"

@implementation Iphone
-(void)setBattery:(Battery *)battery
{
    //当不小心把别的battery set后dealloc却释放的是最后一个battery
    //因此要判断两个battery对象是否一样
    //如果不一样就把以前的对象realease
    if(battery != _battery) {
        [_battery release];
        // set battery对象后这个battery就要被销毁
        // 以后需要访问这个battery对象时候就会发生野指针错误
        // 因此 给这个对象retain操作
        _battery = [battery retain];
    }

}

-(Battery *)battery
{
    return  _battery;
}

-(NSString *)brand
{
    return _brand;
}

-(void)setBrand:(NSString *)brand
{
    
    _brand = brand;
}

-(void) dealloc
{
    //释放电池内存
    [_battery release];
    NSLog(@"%@手机被销毁", _brand);
    [super dealloc];
}

-(void) say
{
    NSLog(@"手机电池是:%@", _battery);
}
@end

//main.m
#import <Foundation/Foundation.h>
#import "Battery.h"
#import "Iphone.h"



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

    @autoreleasepool {
        //声明一个电池对象 计数器为1
        Battery *battery = [[Battery alloc] init];
        Battery *battery1 = [[Battery alloc] init];
        
        //声明一个手机对象 计数器为1
        Iphone *iphone = [[Iphone alloc] init];
        
        iphone.brand = @"iphone";
        
        battery.brand = @"iphone专用电池";
        
        //battery 计数器为2
        iphone.battery = battery;
        
        //battery 计数器为1
        [battery release];
        
        //
        //[iphone say];
        
        battery1.brand = @"LG专用电池";
        
        // battery计数器为0 对象被销毁 battery1对象计数器为2
        iphone.battery = battery1;
        
        // battery 对象计数器为1
        [battery1 release];
        
        // battery1计数器为0对象被销毁,iphone对象计数器为0对象被销毁
        [iphone release];
        
        
        
    }
    return 0;
}

六.@property介绍

    你已经了解了如何正确的使用set方法管理内存,可能这时候你会觉得上面的代码管理内存是在是麻烦。每个对象都要在头文件声明set,get方法,在.m中实现。而且每个set都要对设置的对象进行判断,release旧的对象,retain对象。只是实现这么简单的功能却要写这么多行代码。此时的你会不会在思考如何能让代码更少一点呢?
  介绍:在头文件中使用@property声明对象的属性在头文件中就不需要写对应的set,get声明了,编译器会帮你完成。那在.m文件中怎么实现呢?可以使用@synthesize声明对应的属性编译器就会帮你生成set,get方法的实现。在xcode4.5后@property也可以实现生成set,get方法的实现。

  属性:set方法内存管理的参数
     retain : release旧值,retain新值(适用oc对象)
     copy:release旧值,copy新值
     assign:直接赋值(默认,适用基本数据类型)

     是否要生成set方法
      readwrite:同时生成set,get声明(默认)
      readonly:只会生成get声明

     多线程管理
     nonatomic:性能高
     atomic:性能低(默认)
#import <Foundation/Foundation.h>
//电池类头文件
@interface Battery : NSObject
{
    //电池品牌
//    NSString *_brand;
}
@property (retain) NSString *brand;
//- (NSString *) brand;
//
//- (void) setBrand:(NSString *)brand;
@end


//电池类实现
#import "Battery.h"

@implementation Battery

//-(NSString *)brand
//{
//    return _brand;
//}
//
//-(void)setBrand:(NSString *)brand
//{
//        _brand = brand;
//}
//- (NSString *) description
//{
//    return @"I'm a battery";
//}

//重写dealloc方法
- (void)dealloc
{
    //打印
    NSLog(@"%@battery被销毁",_brand);
    //调用父类dealloc方法
    [super dealloc];
}
@end


#import <Foundation/Foundation.h>
@class Battery;
@interface Iphone : NSObject
{
//    Battery * _battery;
//    
//    NSString *_brand;
}

@property (retain) Battery * battery;

@property (retain) NSString *brand;

//-(void) setBattery:(Battery *)battery;
//
//-(Battery *) battery;
//
//- (NSString *) brand;
//
//- (void) setBrand:(NSString *)brand;
@end


#import "Iphone.h"
#import "Battery.h"

@implementation Iphone
//-(void)setBattery:(Battery *)battery
//{
//    //当不小心把别的battery set后dealloc却释放的是最后一个battery
//    //因此要判断两个battery对象是否一样
//    //如果不一样就把以前的对象realease
//    if(battery != _battery) {
//        [_battery release];
//        // set battery对象后这个battery就要被销毁
//        // 以后需要访问这个battery对象时候就会发生野指针错误
//        // 因此 给这个对象retain操作
//        _battery = [battery retain];
//    }
//
//}
//
//-(Battery *)battery
//{
//    return  _battery;
//}
//
//-(NSString *)brand
//{
//    return _brand;
//}
//
//-(void)setBrand:(NSString *)brand
//{
//    
//    _brand = brand;
//}

-(void) dealloc
{
    //释放电池内存
    [_battery release];
    NSLog(@"%@手机被销毁", _brand);
    [super dealloc];
}

-(void) say
{
    NSLog(@"手机电池是:%@", _battery);
}
@end




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

    @autoreleasepool {
        //声明一个电池对象 计数器为1
        Battery *battery = [[Battery alloc] init];
        Battery *battery1 = [[Battery alloc] init];
        
        //声明一个手机对象 计数器为1
        Iphone *iphone = [[Iphone alloc] init];
        
        iphone.brand = @"iphone";
        
        battery.brand = @"iphone专用电池";
        
        //battery 计数器为2
        iphone.battery = battery;
        
        //battery 计数器为1
        [battery release];
        
        //
        //[iphone say];
        
        battery1.brand = @"LG专用电池";
        
        // battery计数器为0 对象被销毁 battery1对象计数器为2
        iphone.battery = battery1;
        
        // battery 对象计数器为1
        [battery1 release];
        
        // battery1计数器为0对象被销毁,iphone对象计数器为0对象被销毁
        [iphone release];
        
        
        
    }
    return 0;
}

七.自动释放池(autorelease pool)

概念:一个用来存放对象的池子,并且能够自动释放。当自动释放池被销毁时,会向池子中的所有对象发送一条release消息。当给一个对象发送autorelease消息时,实际上是把该对象添加到释放池中。在ios程序中,会创建无数个自动释放池,这些池子已栈的形式存在。
     注意事项:
1.占用内存大的对象不要随便使用autorelease。
     使用好处:
1.不再关心对象释放的时间。
2.不再关心什么时候调用release。
    代码如下:
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        //调用完autorelease方法后,对象的计数器不变	
        //声明一个电池对象 计数器为1
        Battery *battery = [[[Battery alloc] init] autorelease];
        Battery *battery1 = [[[Battery alloc] init] autorelease];
        
        //声明一个手机对象 计数器为1
        Iphone *iphone = [[[Iphone alloc] init] autorelease];
        
        iphone.brand = @"iphone";
        
        battery.brand = @"iphone专用电池";

        iphone.battery = battery;
        
        
        battery1.brand = @"LG专用电池";
        
        iphone.battery = battery1;
              
        
        
    }
    return 0;
}


     
     
     




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值