关闭

黑马程序员——OC基础03—内存管理

187人阅读 评论(0) 收藏 举报
分类:

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

一、内存管理的基本管理

1.由于移动设备的内存有限,所以我们必须确保在需要的时候分配内存,在程序运行结束的时候释放占用的内存。如果只分配而不释放,就会发生内存泄漏。

2.管理的范围:只对任何继承NSObject的对象(存放堆区的),而对其他的基本数据无效。

3.原理:
对象所有权:任何自己创建的对象都归自己所有。
如果一个对象有指向其他对象的实例变量,则称该对象拥有这些对象。如果一个函数创建了一个对象,则称该函数拥有这个对象。

引用计数器:是判断对象是否要回收的依据。当一个对象没有了拥有者时,它的的引用计数器归0,此时需要回收。

当某段代码需要访问一个对象时,给系统发送retain消息,该代码将该对象的引用计数器加一,表示“我要访问该对象”。

当某段代码结束访问时,给系统发送release消息,将对象的引用计数器减一,表示不再访问该对象。

直到引用计数器的值retainCount为0时,表示不再有代码访问该对象了。因此它将被销毁,其占用的内存被系统回收以便重用。

当对象被销毁时,会调用系统的dealloc方法。但是需要重写。

重写dealloc

-(void)dealloc{

NSLog(@“XXXXX dealloc”);
[super dealloc];   //   super 的作用是访问父类的dealloc方法

Person *p1=[Person new];
[p1 retainCount]; //此时为1
Person*p2=p1;
[p2 retainCount];//此时还是为1;

分类:
MRC(手动内存管理)
ARC(自动内存管理)Xcode自动默认的。
垃圾回收

二、原则
1.
如果对象有人使用,就不应该被回收;
谁创建 谁release;
谁retain 谁release;
有始有终;
2.

内存管理的研究内容:
1)野指针: 定义指针时候没有初始化, 或则是指向的空间内容已经被释放。
2)内存泄露: 栈区的p指针已经被释放,而堆区的空间还未释放。

{

    Person *p1=[Person new];

} //此刻造成内存泄露

3.

单个对象的内存管理

如果对象已经被释放,那么这个对象称为僵尸对象;Xcode 中勾选了僵尸对象判断,则系统会报错。如果没有勾选,
被释放后的对象还是能够访问曾经指向的空间,但是此刻是以野指针访问的。

为了避免使用僵尸对象可以在对象释放后将对象指向nil。

4**set方法的内存管理**

在一个类中 存在其他的关联关系的对象,set方法书写时要release 旧值,retain新值。

-(void)setDog:(Dog*)dog{


    if(_dog!=dog){
        [_dog release];
        [_dog=dog retain ;]

    }

}

当为基本数据类型时,可以直接赋值。

  1. MRC下@property的参数

1)原子性
automic 对属性加锁
nonautomic 对属性不加锁 不安全
读写性:
readwrite 读写
readonly 可读
内存管理:
assign 直接赋值
retain release旧值 retain新值
copy

@property (nonatomic ,assign)Car* car;
如果对对象直接赋值,会造成内存泄露。
在一个类中有关联其他对象的时候用retain。



如果要替换setter和getter的名称,可以
@propertynonatomic ,setter=isVip:)
@propertynonatomic ,getter=isVip:)

6.@class 的使用
@class 类名A;
它的作用就是告诉编译器,类A只是一个类,对于类中有哪些属性和方法,不去判断检测。
好处是 当A中的内容发生了改变,不需要重新进行编译。,他可以解决循环引用的问题。

7.循环retain
循环retain会造成两个对象都发生内存泄露,为防止这种现象
1)让其中的一个对象多释放一次
2)一个对象用retain,另一个对象用assign;

三、自动释放池
1.当[p autorelease]时,会将p以栈的形式存放在栈区的释放池中,此时retainCount不变;
2.自动释放池结束时候,会给池中发送一条release消息,相当于一次release。
3.放到释放池中的代码需要手动加入到释放池[p release];才能生效。
4.autorelease的嵌套,作用域就在本代码块的区间内。

5.快速创建对象(用构造方法)

要求: 1)快速创建对象
            2)程序结束时能将对象自动释放

构建一个student类,通过重写构造方法实现创建学生对象的时候能够默认制定的年龄。

//**Person.m**
#import <Foundation/Foundation.h>

@interface Student : NSObject
@property(nonatomic,assign)int age;

-(instancetype)initWith:(int)age;
+(instancetype)studentWith:(int)age;
@end

//**Person.h**
@implementation Student
+(instancetype)studentWith:(int)age{ //instancetype 的作用要优于id,是因为前者能够智能判断赋值的指针变量的类型。

    return [[[self alloc]initWith:age]autorelease];  //自定义 且自动加入释放池

    }


-(instancetype)initWith:(int)age{

    if (self==[super init]) { //重写构造方法
        _age=18;




    }
    return self;

}
-(void)dealloc{

    NSLog(@"self dealloc");

    [super dealloc];
}
@end


//**main.m**

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

        Student*stu1=[Student studentWith:18];
        Student *stu2=[Student studentWith:20];

        NSLog(@"%d",stu1.age);
        NSLog(@"%d",stu2.age);

    }
    return 0;
}

四、ARC
1.正常创建对象,不用手动释放。
2.自动引用计数,当没有强指针指向时,ARC自动释放对象。
3.重写dealloc方法时不用写[super dealloc];
4.@property参数中没有了retain ,换成了强指针__strong 和弱指针__weak。

5.

Car *c1=[Car new];
c1=nil;
此时c1的指向发生改变,无强指针指向的空间瞬间被释放。
作用同于
__weak Car*c2=[Car new];
建立变量时候直接被释放,无效表达式。



6.ARC下的循环引用问题

strong P.dog=dog1;
Strong dog.owner= p1;
在这种情况下,即使当代码块运行结束时dog1和p1的指向都还只向着对方,仍然不会释放,造成内存泄露。
解决方案:其中一个对象设置为strong,另一个设置为weak;

Dog.h

#import <Foundation/Foundation.h>
@class Person;//避免循环引用
@interface Dog : NSObject

@property (nonatomic,strong)Person* owner;
//owner 的指针是强指针
-(void)run;

@end

Dog.m
#import "Dog.h"

@implementation Dog
-(void)run{

    NSLog(@"狗在跑。");
}

-(void)dealloc{

    NSLog(@"dog dealloc");
}
@end


 Person.h

#import <Foundation/Foundation.h>
#import "Dog.h"
@interface Person : NSObject
@property(nonatomic,strong)Dog* dog;
//dog的指针也是强指针
-(void)liuDog;
@end
@implementation Person
-(void)liuDog{

    NSLog(@"人在遛狗。");

}

-(void)dealloc{

    NSLog(@"Person dealloc");
}
@end


main.m

#import "Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p1=[[Person alloc]init];
        Dog*byd =[Dog new];
        p1.dog=byd;
        byd.owner=p1;
//此时两个指针互相指向对方,而且都是强指针,所以即使在ARC的情况下,当函数体结束时,两个指针及指向的空间都不会释放,造成内存泄露。
解决的方案就是将其中之一的对象的属性改为weak。


        [p1 liuDog];


    }
    return 0;
}

7.ARC中如果弱指针指向的对象不见了,则弱指针做清空操作(指向nil)。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2193次
    • 积分:157
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档