IOS开发OC基础知识(二) 内存管理

93 阅读5分钟

创建对象

1.分配内存空间,存储对象
2.初始化成员变量
3.反回对象的指针地址

 1.对象在完成创建的同时,内部会自动创建一个引用计数器,这个计数器,是系统用来判断是否回收对象的唯一依据,当我们的引用计数retainCount = 0的时候,系统会毫不犹豫回收当前对象

 2.[对象 release]  reatinCount - 1

 3.[对象 retain]   reatinCount + 1 ,返回self

 4.我们的引用计数retainCount = 0的 对象就被销毁了

 5.dealloc函数,当一个对象要被销毁的时候,系统会自动调用dealloc函数,通知对象你将要被销毁

 内存管理原则(配对原则):只要出现了 new,alloc,retain,就一定配对出现一个release,autorelease

手动内存管理研究问题方法

1.野指针操作

2.内存泄漏

    //EXC_BAD_ACCESS 访问了不可访问的内存空间

    //被系统回收的对象我们称之为僵尸对象

默认情况下xcode为了提高编码效率,不会时时检查僵尸对象

如果你确定当前作用于中的对象已经不会再被使用了,为了防止野指针操作,通常我们会把不在使用的指针变量赋值为nil

内存泄漏第一种情况

     Person * p = [[Person alloc] init];
     p.age = 20;
     NSLog(@"%@",p);
     [p retain];
     [p retain];
     [p release];  
     //只要对象的retainCount != 0 就会一直存在在内存中
     //内存泄漏指的就是,不再被使用的对象,一直在内存中没有被销毁

内存泄漏第二种情况

     //retainCount = 1
     Person * p = [[Person alloc] init];
     p.age = 20;
     [p run];
     p = nil;
     [p release];//[nil release];

内存管理原则(配对原则):只要出现了new,alloc,retain方法,就要配对出现release,autorelease

对象存入到自动释放池中,当这个池子被销毁的时候他会对池子中所有的对象进行一次release操作

@autoreleasepool

示例1

    大括号代表池子的作用域
    @autoreleasepool {
    //release 功能 retaincount - 1
    //autorelease 好像功能也是 retaincount - 1 ?
    Person * p = [[Person alloc] init];
    [p release];//retainCount立即 -1
    [p autorelease]; //autorelease方法的作用只是将对象放入到池子中,然后返回一个self
     NSLog(@"asdfasdf");
     }   //代表,池子将要被销毁,对池子中所有的对象进行一次release操作,[p release] 
     0
     //autoreleasepool我么可以自己随意的创建

示例2

    //不管你这个对象时在@autoreleasepool 之内创建的还是在之外创建的,只要你在池子中调用了autorelease那么这个对象就会被放入到池子中
    Person * p = [[Person alloc ] init];
    @autoreleasepool {
       [p autorelease];
    }   //p 0

示例3

    //1 只有在自动释放池的作用域中调用对象的autorelease方法才能够正确的讲对象放入到池子中
    Person * p = [[Person alloc] init];
    [p autorelease];
    NSLog(@"aaaa");
    @autoreleasepool {

    }
    NSLog(@"bbb");

示例4

    Person *  p = [[Person alloc] init];
    @autoreleasepool {
        [p autorelease];//加入第一次
        [p autorelease];//加入第二次
        NSLog(@"abc");
    }//[p release]0 [p release]
     NSLog(@"cbd");

示例5

    Person * p = [[Person alloc] init];
     @autoreleasepool {
         @autoreleasepool {
            [p autorelease];
         }//?[p release] 0
    }

ARC简单,不用程序员在去管理内存

1.强指针 Strong

2.弱指针 weak

只要有强指针指向一个对象,那么系统就不会回收该对象

只要没有强指针指向对象,系统立即回收该对象

弱指针不影响,对象被回收

默认情况下,所有的指针都是强指针类型

创建出来就会立即被释放掉,应为没有强指针指向该对象

    __weak Person * p = [[Person alloc] init];
    NSLog(@"adfadf");
    Person * p = [[Person alloc] init];
    __weak Person * p1 = p;
    p = nil;
- (void)dealloc {
    //[super dealloc];不能够在调用
      //releae retain 在ARC机制中不能够在去手动调用
    NSLog(@"Person 被释放了");
}

//@property(nonatomic,retain)Car * car;

//ARC机制 strong 对象,手动内存管理的retain关键字,(一定能够都是应用在对象类型变量上)

//ARC机制中的 weak 对象手动内存管理的assign关键字,(一定能够都是应用在对象类型变量上)

@property (nonatomic,strong)Car * car;//强直阵类型的对象,会影响对象回收

@property (nonatomic,weak)Car * car2;// 弱指针类型的对象,不会影响对象的回收

//@property (nonatomic,assign)Car * car3;//造成迷惑,会导致许多程序员搞不清这个变量到底是stong类型的还是weak类型

//ARC机制下 基本数据类型的@property参数使用,与手动内存管理完全一致

@property (nonatomic,assign)int age;

//当出现类循环应用的时候,只需要把一方面的Strong引用改为weak,并且在.h文件中使用@class 类名的方式,通知.h文件类的存在

@property (nonatomic,weak)Person * p;

//不能在分类中生成员变量

//如果分类中定义实现了与原类中相同的方法,那么原类中的方法相当于被覆盖掉了

//在实际的开发中,最好不要出现方法覆盖

//数据类型

//1.作为参数传递

//2.作为函数的返回值

//3.声明成变量

//int 4 float double 8 char

        //更加合理的分配内存空间
        int ca =10;
        //对象类型 NSObject * obj
        //id
        //BOOL
        //block 指向函数的指针比较像
        //SEL
        void (*myPoint)() = test;
        myPoint();
        //block就是弥补了 指向函数的指针,不能够直接保存一个函数体(代码块)
        void (^myBlock)() = ^{
            NSLog(@"test");
        };
        myBlock();
        int (^sumBlock)(int a, int b) = ^int (int a, int b) {
            return a + b;
        };
        int result = sumBlock(10,20);
        NSLog(@"result = %d",result);
        //如果想要改变,block代码块之外的变量值,就必须在变量前加入
        //__block关键字