Objective-C基础3

1.OC内存管理

1)范围:管理任何继承NSObject的对象,对其他的基本数据类型无效(堆区),否则会造成内存泄露

2)原理:任何对象都可能有用一个或多个所有者,只要一个对象至少还拥有一个所有者,它就会继续存在

3)对象的引用计数器,retain(+1)、release(-1)、retainCount得到引用计数器的值

4)内存管理的分类:MRC(手动管理)、ARC(自动管理)、垃圾回收(不支持)

2.引用计数器的使用

dealloc:释放对象

先调用[super dealloc]

我们创建一个项目,默认是ARC模式,先修改

//
//  main.m
//  内存管理
//
//  Created by fanyafang on 15/11/6.
//  Copyright © 2015年 itcast. All rights reserved.
//

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p =[[Person alloc]init];
        
        NSUInteger count=[p retainCount];
        
        NSLog(@"%lu",count);
        
        //Person *p2=p;//不变
        //Person *p2=[p retain];//加1
        [p retain];//加1

        [p release];//减一
        [p release];//减一自动调用dealloc方法
        //证明p的空间被释放,可以在Person类中重写dealloc方法
    }
    return 0;
}

3.内存管理的原则

1)只要有人使用这个对象,这个对象就不会被回收

2)只要你想使用这个对象,那么就应该让这个对象的引用计数器加1

3)当你不想使用这个对象时,应该让对象的引用计数器减1

4)谁创建(new、malloc、copy)谁release

5)谁retain谁release

4.如果一个对象已经被释放了,这个对象就成为僵尸对象,再去使用这个对象就没有意义,默认不报错,需要开启僵尸对象检测

不能使用retain让僵尸对象起死回生

5.对象nil 类Nil NULL NSNull是一个对象

避免使用僵尸对象的方法是,对象释放以后,给对象赋值为nil

6.多个对象的内存管理

在set函数中先release实例对象,再retain传入的对象

//如果是同一个对象的话就不需要release和retain

if(_car!=car){

  [_car release];

  _car=[car retain];

}

在dealloc中,release实例对象

[_car release];

7.@property参数

1.原子性atomic  nonatomic

2.读写readwrite readonly

3.内存管理assign retain copy

替换get方法名称setter=isVip,get方法名称getter=isVip

8.@class的使用

使用import引入头文件时,如果头文件的内容发生了变化,此时所有引用这个头文件的类都需要重新编译

使用@class 类名;代替import

告诉编译器xxx是一个类,不需要重新编译

但是使用时会有提示错误,解决办法,在.m文件中再import一次

@class的可以解决循环引入问题,A类和B类互相import,使用class不会报错

9.循环retain会导致两个对象都会内存泄露

防止方法:1)让某个对象多释放一次(注意顺序)

2)推荐方法:一端使用assign,另一端使用retain

10.NSString对象

11.@autoRelease

如果一个方法需要放回一个新建的对象,该对象何时释放?

方法内部不会释放,因为这样做会将对象立即释放而返回一个空对象,调用者也不会主动释放该对象

这个时候就发生了内存泄露

1)@autoreleasepool {}创建自动释放池

2)[对象 autorelease];//加入自动释放池,发送消息,释放池结束的时候调用对象的release

autorelease的嵌套:
1)自动释放池的栈结构和内存的栈是不一样的

2)对象存在栈顶的自动释放池中

12.id和instancetype的区别

instancetype可以智能帮我们判断赋值的指针变量的类型和方法的返回值类型是否一致

13.autorelease的使用场景

如父类是Person在父类的person方法中使用autorelease,Student继承Person类

//
//  Person.m
//  OC03
//
//  Created by fanyafang on 15/11/7.
//  Copyright © 2015年 itcast. All rights reserved.
//

#import "Person.h"

@implementation Person
+(instancetype)person{
    return [[[self alloc]init]autorelease];
}
-(void)dealloc{
    NSLog(@"Person释放了!");
}
@end

在main方法中,创建自动释放池

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //Person *p=[Person person];
        Student *student = [Student person];
    }
    return 0;
}

14.重写初始化方法

//
//  Student.h
//  OC03
//
//  Created by fanyafang on 15/11/7.
//  Copyright © 2015年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Student : NSObject
@property(nonatomic,assign) int age;
-(instancetype)initWithAge:(int)age;
+(instancetype)StudentWithAge:(int)age;
@end
//
//  Student.m
//  OC03
//
//  Created by fanyafang on 15/11/7.
//  Copyright © 2015年 itcast. All rights reserved.
//

#import "Student.h"

@implementation Student
-(void)dealloc{
    NSLog(@"释放了");
}
-(instancetype)initWithAge:(int)age{
    if(self=[super init]){
        _age=age;
    }
    return self;
}
+(instancetype)StudentWithAge:(int)age{
    
    return [[[self alloc]initWithAge:age]autorelease];
}
@end
//
//  main.m
//  重写初始化方法
//
//  Created by fanyafang on 15/11/7.
//  Copyright © 2015年 itcast. All rights reserved.
//

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        /*
        Student *stu=[[Student alloc]initWithAge:10];
        NSLog(@"stu age%d",[stu age]);
        [stu release];
         */
        Student *stu=[Student StudentWithAge:20];
        NSLog(@"stu age%d",[stu age]);
    }
    return 0;
}

 

原文地址:https://www.cnblogs.com/fanglove/p/4943756.html