对象内存管理
栈区局部变量 (地址从高到低分配)局部变量的空间会自动回收
堆区存放程序运行过程中动态分配-存储空间(从低到高分配)
管理范围:管理人和继承自nsobject对象,Oc中new类的实例对象类会继承nsobject对象,对其他基本数据类型无效,先释放堆区的,在释放栈区
程序启动的时候就加载到内存(全局变量尽可能少用)由系统自动管理
bss段未初始化的全局变量和静态变量
数据区已经初始化的全局变量静态变量字符串常量
代码段代码编译过后的内容
微信飞机射击的游戏
子弹对象:不在可见区域的时候要释放掉
闪退:软件占用移动内存超过多少M之后就会崩溃,超过20M会发送MemoryWarning消息,回收一些不需要再继续使用的内存空间,比如一些不再使用的对象和变量等,否则程序崩溃
ios的平台内存软件控制的特别好
内存管理的原理及分类
*P的所有权为1,所有者就是自己,分配的存储空间有一个指针指向他
任何自己创建的对象都归自己所有,可以使用alloc,new,开头,或者名字中包含copy
的方法创建对象时,可以使用retain获取一个对象的所有权
对象的引入计数(用来保存当前对象有几个东西在使用它)
retainCount引用计数器
及多少个东西在引用这个对象
一个对象创建之后,最少有一个应用者
没有对象内部,有八个字节存储空间来存储引用计数器
引入计数器作用
1.判断对象是否回收的依据,为0表示要回收了
2.一个对象的值为nil时候,引用计数器为0,但不回收
Person *p=nil;不用回收,因为没有创建内存空间
引用计数器操作
对象的销毁(一)
1.对象被释放的时候,系统发送一条dealloc消息,一般重写dealloc
2.一旦重写就必须在dealloc方法内部调用 [super dealloc ]调用,并且在代码块的最后调用
3.一旦对象被回收,他所占用的存储空间不再可用,坚持使用会导致程序崩溃
OC内存管理分类,
MRC手动管理内存MannuReference Counting 需要手动retain,release,autorelease
ARCautomaticreferencecounting自动引用计数
Garbagecollection垃圾回收ios不支持垃圾回收macos支持
理解mrc尽量使用arc
苹果底层都是MRC,公司历史遗留的项目也有用MRC
手动内存快速入门
关闭ARC方法
#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
//
Person *p = [Person new];
NSLog(@"retain= %ld",[p retainCount]) ;
//typedefunsigned long NSUInteger;
//占八个字节
//NSLog(@"%ld",sizeof([p retainCount]));
//引用计数器 + 1
//Person *p2 = p; //retainCount的还是1
// Person *p2 = [p retain];
//引用计数器 + 1
[p retain];
NSLog(@"retain= %ld",[p retainCount]) ;//2
[p release];
NSLog(@"retain= %ld",[p retainCount]) ;//1
[p release];
}
return 0;
}
2015-12-17 15:11:23.843内存管理-MRC管理[8484:1270933] retain = 1
2015-12-17 15:11:23.845内存管理-MRC管理[8484:1270933] retain = 2
2015-12-17 15:11:23.845内存管理-MRC管理[8484:1270933] retain = 1
2015-12-17 15:11:23.846内存管理-MRC管理[8484:1270933]内存已经挂了
Program ended with exit code: 0
.m文件实现dealloc
#import"Person.h"
@implementation Person
-(void)dealloc{
NSLog(@"内存已经挂了");
[superdealloc];
}
@end
内存管理:对象如果不再使用,就应该回收它的空间,防止造成内存泄露
内存管理范围:所有的集成了NSObject的对象内存管理
基本数据类型的数据内存不需要手动进行管理
内存管理原则:
#import<Foundation/Foundation.h>
#import"Dog.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Dog *bd = [[Dogalloc]init];
Dog *jd = [bdretain];//指向同一个空间
NSLog(@"jd= %ld",[jd retainCount]);//2
NSLog(@"bd= %ld",[bd retainCount]);//2
//bd需要retain释放两次谁retain谁释放
[bd release];
[bd release];
}
return 0;
}
内存管理研究的内容
1).野指针 1.定义的指针变量没有初始化,2.指向的空间已经释放
2).内存泄露
Person *p ={Person new];
P在栈区
[Person new];堆区
如果栈区的p已经释放掉了,而堆区的空间没有释放,堆区的空间就是释放了
#import<Foundation/Foundation.h>
#import"Dog.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Dog *dg = [Dognew];
[dgrelease];//释放掉之后不能再进行 [dg retain]
//开启僵尸对象检测后,dg称为野指针,会报错,默认情况下不报错
[dg eat];
}
return 0;
}
单个对象的野指针问题
再次运行就报错
#import<Foundation/Foundation.h>
#import"Dog.h"
void test(){
Dog *dg = [Dog new];
[dg release];
//nil给 nil发送任何消息都没有效果
dg = nil ;
//避免了使用将是对象的方法,对象释放了以后,给对象赋值为nil
[dg retain];
}
int main(intargc,const char* argv[]) {
@autoreleasepool {
//泄露情况1:没有release的对象一定是泄露的
//Dog*dg = [Dog new];
//内存泄露情况2没有遵守谁retain谁 release
//少一次都会造成内存泄露
Dog *dg = [Dognew];
[dg retain];
[dg release];
//内存泄露的情况3
//不当的使用nil
Dog *dg2 = [Dog new];
dg2 = nil;
[dg2 eat];
[dg2 release];
//第四种情况调用的方法中多retain了一次
Dog *dg3 = [Dognew];
[dg3 compareColorWithOther:dg3];
[dg3 release];
}
return 0;
}
//让对象的引入金属器 +1
#import"Dog.h"
@implementation Dog
-(void)eat{
NSLog(@"汪星人正在享受午餐");
}
-(BOOL)compareColorWithOther:(Dog *)dog{
[dog retain];//让对象的引入金属器+1
return YES;
}
-(void)dealloc{
NSLog(@"Dog类已经释放");
[superdealloc];
}
@end
多个对象野指针的问题
#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Person *p = [Personnew];
Car *byd = [Carnew];
byd.speed = 102;
[p setCar:byd];
[bydrelease];//如果Car对象已经销毁,p成了野指针
//调用出现严重的报错
[p goLasa];
}
return 0;
}
#import<Foundation/Foundation.h>
#import"Car.h"
@interface Person :NSObject
{
Car *_car;
}
-(void)goLasa;
-(void)setCar:(Car*)car;
@end
#import"Person.h"
@implementation Person
-(void)setCar:(Car*)car{
_car = car;
}
-(void)dealloc{
NSLog(@"Person对象销毁");
[superdealloc];
}
-(void)goLasa{
[_carrun];
}
@end
#import<Foundation/Foundation.h>
@interface Car :NSObject
{
int _speed;
}
-(void)setSpeed:(int)speed;
-(void)run;
@end
#import"Car.h"
@implementation Car
-(void)dealloc{
NSLog(@"车类释放");
[superdealloc];
}
-(void)setSpeed:(int)speed{
_speed = speed;
}
-(void)run{
NSLog(@"凤姐开着以%d码的速度往拉萨开qu1",_speed);
}
@end
多个对象内存泄露的问题
#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Person *p = [Personnew];
Car *byd = [Carnew];
byd.speed = 102;
[p setCar:byd];
[byd release];
[p goLasa];
[p goLasa];
[p goLasa];
[p goLasa];
//
[p release];
}
return 0;
}
#import"Person.h"
@implementation Person
-(void)setCar:(Car*)car{
_car = [car retain];//retain
}
-(void)dealloc{
[_cardealloc];//先销毁车子,再销毁人的类
NSLog(@"Person对象销毁");
[superdealloc];
}
-(void)goLasa{
[_carrun];
}
@end
原对象无法释放的问题
#import"Person.h"
@implementation Person
-(void)setCar:(Car*)car{
//如果是同一个对象就不需要再release再retain一次
if(_car !=car){
[_carrelease];//release旧值
_car = [carretain];//retain新值
}
}
-(void)dealloc{
[_cardealloc];//先销毁车子,再销毁人的类
NSLog(@"Person对象销毁");
[superdealloc];
}
-(void)goLasa{
[_carrun];
}
@end
set方法内存管理原则
原则:如果一个类中,有其他类的对象(关联关系)
set方法书写的时候,要判断是否同一个对象,release
@property参数
数据库事务处理
当存钱的事务没有完成的时候,另外一边没办法取钱的。就是原子性
数据回滚
Nonatomic不涉及多线程的情况下,不考虑安全的情况下高性能,一般使用这个
Atomic低性能默认
内存管理相关参数
Retain 在类中有关联其他对象的时候,@property(nomatic,retain)这个对象需要retain,先release原来的值,然后再retain新值(在set方法内部进行新对象和旧对象是否相同的判断,
新对象则release,再retain)
Assign 直接赋值,没有进行retain操作 ,实例变量是基本数据类型的时候,或者不写(默认值)
Copy :先release再copy新值
#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Person *p = [Personnew];
[p isVip:YES];
if (p.isVip){
NSLog(@"是vip客户");
}
}
return 0;
}
#import<Foundation/Foundation.h>
@interface Person :NSObject
@property (nonatomic,assign,setter=isVip:,getter=isVip)BOOL vip;
@end
#import<Foundation/Foundation.h>
#import"Seller.h"
#import"Buyer.h"
#import"Goods.h"
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Person *person = [Person new];
[person release];
Buyer *buyer = [Buyer new];
[buyer release];
Goods *goods = [Goods new]; //1
Seller *seller = [Seller new];//1
seller.good = goods;//2
[goods release];//1
[seller release];
}
return 0;
}
#import<Foundation/Foundation.h>
typedef struct Time{
int minute ;
int hour;
int second ;
}myTime;
typedef struct Date{
int year ;
int month ;
int day ;
myTime time;
}myDate;
@interface Goods :NSObject
@property(nonatomic,assign)float productPrice;
@property(nonatomic,assign)float weight;
@property(nonatomic,retain)NSString *productName;
@property(nonatomic,retain)NSString *productImage;
@property(nonatomic,assign)myDate productDate;
@property(nonatomic,assign)myDate expireDate;
@end
#import"Goods.h"
@implementation Goods
-(void)dealloc{
[_productNamerelease];
[_productImagerelease];
NSLog(@"Goods释放");
[superdealloc];
}
@end
#import<Foundation/Foundation.h>
typedefenumsex{KSexFemale,KSexMale,KSexRY} iSex;
@interface Person :NSObject
@property (nonatomic,retain)NSString *name;
@property (nonatomic,assign)iSex sex;
@property (nonatomic,assign)int age ;
@property (nonatomic,assign)float weight;
@end
#import"Person.h"
@implementation Person
-(void)dealloc{
[_namerelease];
NSLog(@"Person释放");
[superdealloc];
}
@end
#import"Person.h"
@interface Buyer :Person
@end
#import"Buyer.h"
@implementation Buyer
-(void)dealloc{
NSLog(@"BUyer释放");
[superdealloc];
}
@end
#import"Person.h"
#import"Goods.h"
@interface Seller :Person
@property(nonatomic,retain)Goods *good;
@end
#import"Seller.h"
@implementation Seller
-(void)dealloc{
[_goodrelease];
[superdealloc];
}
@end
#import可能出现重复引入的问题,A类引入B类头文件,B类引入A类头文件,循环引入问题
@class可以解决这个问题。
#import作用:把要引入的头文件拷贝到#import处
如果某个.h文件发生变化
@class类名;
在.m文件中导入 person.h头文件,运行时候检查,效率提升一半, 告诉编译器她的属性和方法
@class即便你的类变化了,也不会重新编译
如果xxx文件内容发生了改变,而不需要重新编译
#import<Foundation/Foundation.h>
#import"A.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
A *a = [Anew];
[a test];
}
return 0;
}
#import<Foundation/Foundation.h>
@interface Person :NSObject
@property (nonatomic,assign)int age;
@end
#import"Person.h"
@implementation Person
@end
#import<Foundation/Foundation.h>
@classPerson;
@interface A :NSObject{
Person *_person;
}
-(void)test;
@end
#import"A.h"
#import"Person.h"
@implementation A
-(void)test{
_person = [Personnew];//需要实例化一次
_person.age =10 ;
NSLog(@"Person age =%d",_person.age);
}
@end
循环retain问题set方法给retain了一次
使用@class解决循环引用的问题
1.让某个对象多释放一次 (注意顺序)
2.其中一端设置为assign
#import<Foundation/Foundation.h>
#import"Dog.h"
#import"Person.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Person *p = [Personnew];
Dog *d = [Dognew];
p.dog = d ;//2
d.owner = p ;//2
//retain + 1 @peoperty参数为 retain
//循环引用导致内存泄露
//
[p release];
[d release];
//释放一次之后,p对象指向d d对象指向p
//[drelease];//0
/*
objc[22430]: Person object 0x100103970 overreleased whilealready deallocating; break on objc_overrelease_during_dealloc_error to debug
*/
}
return 0;
}
#import<Foundation/Foundation.h>
//人拥有一条狗
@classDog;
@interface Person :NSObject
@property(nonatomic,retain)Dog *dog;
@end
#import"Person.h"
#import"Dog.h"
@implementation Person
-(void)dealloc{
[_dogrelease];
NSLog(@"Person对象已经释放");
[superdealloc];
}
@end
#import<Foundation/Foundation.h>
@classPerson;
@interface Dog :NSObject
@property (nonatomic,assign)Person *owner;
@end
#import"Dog.h"
#import"Person.h"
@implementation Dog
-(void)dealloc{
// [_ownerrelease ];
NSLog(@"Dog对象已经释放掉");
[super dealloc];
}
@end
1.p.dog =d ; //此时d的rc值为2 | d并没有真的释放 |
d对象为rc = 1
_dog对象的地址值变为nil
2.d.owner =p ; //此时p的rc值为2
Release一次之后两个局部对象都没有了,内存堆区对象互相指向,如下结果,对象为rc都为1
让 p再release一次,_dog对象指向d,_dog先释放,指向的_owner对象也要释放,d的rc值变为0,
objc[22690]: Person object 0x100201450 overreleasedwhile already deallocating; break on objc_overrelease_during_dealloc_error todebug
2015-12-28 18:28:48.631 retain循环使用[22690:2709503] Dog对象已经释放掉
2015-12-28 18:28:48.632 retain循环使用[22690:2709503] Person对象已经释放
Program ended with exit code: 0
栈区地址最高
定义的字符串,字符串是在常量区,如果你的字符串在常量池已经存在,不会分配内存空间
stringWithString
[NSStringalloc] initWithString
NSString *str =@"abc";
在常量区
stringWithFormat是在堆区
堆区不需要释放,没有alloc也不用释放
[NSStringalloc]initWithFormat最好是release一次
尽量不要使用retainCount这个方法,自己创建的对象这么判断是没错的,但是像OCfoundation框架下的对象,用这样的方法判断,可能不准确,
int main(intargc,const char* argv[]) {
@autoreleasepool {
NSString *str1 = @"abc";
NSString *str2 = [NSString stringWithFormat:@"aaa"];
NSString*str3 = [NSStringstringWithString:@"abc"];//字符串常量池
NSString *str4 = [[NSString alloc] initWithFormat:@"aaa"];
NSString *str5 = [[NSString alloc] initWithString:@"abc"];
NSString *str6 = [[NSString alloc] init];
//str6赋了值就存在常量区
int a = 10;//在栈区
NSLog(@"str1= %@,%p,%lu",str1,str1,str1.retainCount);
NSLog(@"str2= %@,%p,%lu",str2,str2,[str2retainCount]);
NSLog(@"str3= %@,%p,%lu",str3,str3,str3.retainCount);
NSLog(@"str4= %@,%p,%lu",str4,str4,str4.retainCount);
NSLog(@"str5= %@,%p,%lu",str5,str5,str5.retainCount);
NSLog(@"str6= %@,%p,%lu",str6,str6,str6.retainCount);
NSLog(@"%p",&a);
}
return 0;
}
2015-12-28 19:30:59.229 NSString类的内存管理问题[22960:2750176] str1 =abc,0x100001030,18446744073709551615
2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str2 =aaa,0x61616135,18446744073709551615
2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str3 =abc,0x100001030,18446744073709551615
2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str4 =aaa,0x61616135,18446744073709551615
2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] str5 =abc,0x100001030,18446744073709551615
2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] str6 =,0x7fff77267d20,18446744073709551615
2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] 0x7fff5fbff70c
Program ended with exit code: 0
%d可能是 -1
常量区的引入器是一个无符号数的最大值
对象的”autorelease”方法代替”relrease”方法可以延长它的生命周期,直接到当前”AutorelreasePool”释放。如果想让此对象的生命周期超过”Autorelease Pool”,还可以再次”retain”,呵呵,有意思吧〜且让我慢慢道来。
Autoreleasepool基本使用
是一种支持引用计数器的内存管理方式
它既可以暂时保存某个对象,然后在内存池自己的排干(drain)的时候对其中的每个对象发送release消息
注意:这里只是发送release消息,如果当时的rc依然部位0,则对象不会释放,可以用该方法来保存某个对象,也要注意保存之后要释放该对象
使用autorelease的好处
1.不需要关系对象的释放时间
2.不需要再关系什么时候调用release
#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
Person *p = [Person new];
@autoreleasepool {
[p run];
NSLog(@"%lu",p.retainCount);
[pautorelease];//把对象p加入到自动释放池
// 注意:加入到自动释放池,引入计数器不会变化
NSLog(@"%lu",p.retainCount);
[p run];
}
//@autoreleasepool结束的时候调用了 release
[p run];
/*
*** -[Person run]: message sent to deallocated instance 0x100203e30
(lldb)
*/
return 0;
}
为什么内存管理只管理oc对象
堆区内存不连续,无法自动释放
堆区通过链表来实现的,链表是指针将内存里物理上不连续的逻辑单元内存单元进行逻辑上的连续
Autorelease注意及错误用法
autorelease将对象的释放延迟
#import<Foundation/Foundation.h>
#import"Person.h"
void test(){
//3.只需要在自动释放吃中调用autorelease,就可以把对象加入到自动释放池
Person *p = [Personnew] ;
@autoreleasepool {
//Person *p = [[Person new] autorelease];
//1)并不是所有的放到自动释放吃中的代码,产生的对象就会自动释放
//如果需要释放,必须加入到自动释放池
//3.接3
[p autorelease];
}
//2.如果对象调用autorelease,不在自动释放池中,不会被释放
//Person*p = [[Person new] autorelease];
}
void test2(){
Person *p = [Personnew] ;
//@autoreleasepool嵌套
//自动释放池以栈的结构存储
//栈顶先进后出对象存在位于栈顶位置的自动释放池中
@autoreleasepool {
@autoreleasepool {
@autoreleasepool {
//同一个对象不要在一个autoreleasepool中autorelease两次
//会发两次消息,登记两次
//不要将循环操作放入到自动释放池中,对象是延迟销毁的,可能造成内存负担
[p autorelease];
}
}
}
}
int main(intargc,const char* argv[]) {
Person *p = [Personnew] ;
@autoreleasepool {
//错误用法3
[p autorelease];
}
[p release];
/*
Person object 0x100300050 overreleased while already deallocating; breakon objc_overrelease_during_dealloc_error to debug
Program ended with exit code: 0ß
*/
return 0;
}
#import<Foundation/Foundation.h>
#import"Person.h"
#import"Student.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
//快速创建对象
Person *p = [Personperson];//person是一个类方法
NSArray *nsa = [NSArray array];
//+(instancetype)array;
NSDictionary *nsd = [NSDictionary dictionary];
//+(instancetype)dictionary;
//动态类型程序直到运行的时候才知道这个对象属于什么类型
Student *stu = [Student person];
//2015-12-29 03:10:42.450 autorelease应用场景[24020:2886223] person run
[stu run];
//因为stu释放的时候调用的[super dealloc]父类是Person
//然后Person又调用一次 [super dealloc]
//所以打印两次 Person dealloc
//存在问题
NSString *str1 = [Student person];
// 如果是instancetype可以智能的判断赋值的指针变量的类型和返回值的类型是否一致
//id 不会存在警告
}
return 0;
}
#import<Foundation/Foundation.h>
@interface Person :NSObject
//将id改为 instancetype
+(instancetype)person;
-(void)run;
@end
#import"Person.h"
@implementation Person
-(void)dealloc{
NSLog(@"Persondealloc");
[superdealloc];
}
-(void)run{
NSLog(@"person run");
}
+(instancetype)person{
return [[[selfalloc]init ]autorelease];//返回的是一个对象空间
}
@end
#import"Person.h"
@interface Student :Person
@end
#import"Student.h"
@implementation Student
-(void)run{
NSLog(@"Studentrun");
}
-(void)dealloc{
NSLog(@"Studentdealloc");
[superdealloc];
}
@end
如果返回值是一个对象,必须使用instancetype
创建一个学生类并初始化年龄,快速创建的构造方法
#import<Foundation/Foundation.h>
#import"Student.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
//Student *stu = [[Student alloc] initWithAge:30];
//NSLog(@"stu.age=%d",stu.age);
//[sturelease];
Student *stu = [Student studentWithAge:30];
NSLog(@"stu.age= %d",stu.age);
}
return 0;
}
#import<Foundation/Foundation.h>
@interface Student :NSObject
@property(nonatomic,assign)int age;
-(instancetype)initWithAge:(int)age;
+(instancetype)studentWithAge:(int)age;
@end
#import"Student.h"
@implementation Student
-(instancetype)initWithAge:(int)age{
//先初始化父类的,并且判断是否初始化成功
if(self = [superinit]){
//初始化子类的
_age = age ;
}
//返回sefl
return self;
}
+(instancetype)studentWithAge:(int)age{
return [[[self alloc]initWithAge:age] autorelease];
}
-(void)dealloc{
NSLog(@"Studentrelease");
[superdealloc];
}
@end
默认情况下,所有指针都是强指针,关键字strong
弱指针,__weak关键字修饰
Arcautomaticreferencecounting自动引入计数,解决了手动内存管理的麻烦
不需要写retain,release,autorelease
三个关键字
机制:
arc是在代码编译的时候,为你在核实的位置插入relese,autorelease
判断准则:
arc只要没有强指针指向对象,对象就会被释放
注意:arc的时候,没有引入计数器,会报错,
当两个对象存在包含关系时,对象1有一个strong指针,并持有他,而对象中有一个weak指针指回对象1,避免了对象循环持有。
弱指针指向的话,先释放然后将weak指针指向nil
arc机制判断
Arc下可以调用dealloc方法,不能调用父类的dealloc方法
arc下但对象的内存管理,不是运行时特性或者垃圾回收机制。
编译的时候,自动加入release,autorelease
#import<Foundation/Foundation.h>
#import"Car.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Car *car = [Carnew];
__strongCar *bwm = car;//指针默认都是强指针
__weak Car*bz = car ;
car =nil;//对象销毁
//让car的指向发生改变,对于car对象来说,没有强指针指向,所以释放对象
//弱指针指向的对象如果被释放,*bz弱指针,自动被赋值为nil
[car run];
}
return 0;
}
只要给对象赋值nil,自动会释放,nil执行任何方法都不会报错
ARC多对象内存管理
#import<Foundation/Foundation.h>
#import"Person.h"
#import"Dog.h"
int main(intargc,const char* argv[]) {
@autoreleasepool {
Dog *jd = [Dognew];
Person *p = [Personnew];
p.dog = jd ;
// jd = nil ;//在@property下 week指针 dog会立即释放,因为对象没有强指针对象了
//jd = nil ;//在@property下 strong指针 jd释放掉之后 _dog指向Dog对象
//先释放Person再释放Dog
}
return 0;
}
互相关联的时候,strong类型指针,结束时候无法释放内存
栈区释放之后p和dog对象释放
但是 _dog和 _owner对象没有释放
将一端设置为弱指针
下方的Dog对象没有强指针指向,所以先释放 ,
所以_owner也没有了
接着就是指向Person对象强指针也消失,所以Person对象释放
UI控件一般使用弱对象指针
arc的使用特点和注意事项
__weakPerson *p1 = [[Personalloc] init];
/*
/Users/chingwei_macpc/Documents/内存管理学习/ARC下循环引用问题/main.m:19:24:Assigning retained object to weak variable; object will be released afterassignment
*/
定义完之后立刻销毁,没有意义
-fno-objc-arc
将一个mrc转换为arc,convertto objectc- arc
左边为改动后,