对retain 和 assign的理解

从开始接触MRC的云山雾罩,到现在略知皮毛,一路辛酸不表,以此为记录总结!

开篇,首先感谢两位前辈的阐述,给我了很大的帮助!

http://blog.csdn.net/yanxunuser/article/details/6792850

http://www.cocoachina.com/bbs/read.php?tid-12760.html

此篇有多处粘贴复制自上述文章,多谢!

一、引用计数是实例对象的内存回收唯一参考

引用计数(retainCount)是OC管理对象引用的唯一依据,调用实例的release方法后,此属性减一,减到0时,对象的dealloc方法会自动被调用,进行内存回收操作,也就是说我们永不该手动调用对象的dealloc方法。

下面是内存管理API的主要操作接口:

  1、alloc,allocWithZone,new(带初始化)

  为内存分配对象,retainCount为“1”,并返回实例

  2、release

  retainCount减“1”,减到0时调用此对象的dealloc方法

  3、retain

  retainCount 加“1”

  4、copy ,mutableCopy

  复制一个实例,retainCount数为“1”,返回此实例。所得到的对象是与其上下文无关的,独立的对象(干净的对象)。

  5、 autorelease

  在当前上下文的AutoreleasePool栈顶的autoreleasePool实例添加此对象,,当pool的retainCount为0的时候,会对里面的所有实例依次release,然后调用pool的dealloc方法,由于它的引用使OC由全手动管理上升到半自动化。

二、OC内存管理准则

A类:是+1操作:1、3、4

B类:是-1操作:2、5(延时释放)

内存管理准则如下:

1,A和B类的调用次数保持一致。

2,为了很好的保障准则1,以实例对象为单位,谁A了就谁B,没有第二者参与!

三、关于属性的assign、retain和copy

例:

  @Property (nonatomic ,assign)NSString *var;

  @Synthsize var;

当使用@Synthsize var后编译器会自动的生成getter 和 setter 方法,这是我们就可以使用“.”操作符来为var赋值。

1、将属性声明为assign时,setter方法的实现是这样的:

- (void)setter:(NSString *)str

  var = str;//仅仅是指针的传递,retainCount 没有发生变化

var = [[NSString alloc]initWithString:@“aaa”];

这时候,[var retainCount]的值会是1;

如果此时我们这样写:

self.var = [[NSString alloc]initWithString:@“aaa”];

此时就会调用var的setter 方法,且这时候,[var retainCount]的值仍会是1;

2、将属性声明为retain时,

  @Property (nonatomic ,retain)NSString *var;

  @Synthsize var;

这时候setter方法的实现是这样的:

- (void)setter:(NSString *)str

  [str retain];

   [var release];

   var = str;

现在就一目了然,此时,需要先将要赋的值的引用计数+1,然后将var指向的对象-1(release),最后,才是将str赋值给var。

这时如果使用赋值:     self.var = [[NSString alloc]initWithString:@“aaa”];

则:[var retainCount]的值会是2;(alloc +1,setter +1)

这样做的目的是为了防止内存被过度释放。

因为: [NSString alloc]initWithString:@“aaa”] 这块内存区域可能不仅仅只有var 指向,可能存在另外一个变量var2也指向此区域,

若此时的var属性为assign,则即使调用赋值方法 self.var = [[NSString alloc]initWithString:@“aaa”];这块内存区域的retainCount仍然是1.

那么如果var2在某处之行了[var2 release],后果就是var2 和var 共同指向的那块内存区域的retainCount值变为0,所以这块内存区域就被释放了,那么var 也就成为了也指针了,这时再引用var就会出现错误,最常见的是 “sentMessage to a dealloc instance”

但是需要注意的是:即使声明为retain属性,我们在赋值的时候也要采用如下形式:

var = [[NSString alloc]initWithString:@“aaa”];

而不是:

self.var = [[NSString alloc]initWithString:@“aaa”];

这样setter方法不会被调用,这块内存的retainCount值为1.

3、关于“.”操作符

"."操作符在OC中是方法的调用,比如:self.str和[self str]是一样的。

如果我在.h文件中声明了一个方法:

-(void)method;

那么,我调用这个方法可以用两种方式:[self method]或self.method。

这样说的话,我们为什么可以用诸如self.str这样的形式来表示一个变量呢,原因就在于OBJC中变量属性的机制。

前面说过,定义一个变量str,加个assign或retain之类的属性后,再用@synthesize就可以生成相应的setter和getter方法了。

这样,对于一个变量,就有了相应的赋值方法,于是,对于self.str这样的写法,实际上就是调用了str对应的setter或getter方法。

换句话说,也是把setter或getter消息发送给和str。str这时就是一个方法名,而不仅仅是变量名了。

所以如果没有对一个变量声明属性,也没有@synthesize来生成setter和getter方法,

那么就不能用self.str这种形式,而只能用[email protected]"aaa",或者str1=str这样的形式来使用变量。

于是也就有了一个的结论:用self.str这种形式,相当于调用setter或getter方法。

也就会执行retain的操作。不用这种形式,就没用调用setter或getter方法,retain的操作也就无从谈起。

4、关于什么时候用“self.”赋值

先从官方文档中拷贝出一个例子:

MyClass.h

@interface MyClass : NSObject {

MyObject *myObject;
}
@property (nonatomic, retain) MyObject *myObject;
@end

MyClass.m

@synthesize myObject;
 
-(id)init{
    if(self = [super init]){
        MyObject * aMyObject = [[MyObject alloc] init];
        self.myObject = aMyObject;
        [aMyObject release];
    }
    return self;
}

现在我们来看看内存管理的内容:

先看间接赋值的:

1.加self.

MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1;(实则是指向的那块内存区域的retainCount)

self.myObject = aMyObject; //myObject retainCount = 2;
 [aMyObject release];//myObject retainCount = 1;//内存泄漏

2. 不加self.

MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1;

myObject = aMyObject; //myObject retainCount = 1;
[aMyObject release];//对象己经被释放

再看直接赋值的:

3.加self.

self.myObject = [[MyObject alloc] init]; //myObject retainCount = 2;//内存泄漏

4. 不加self.

myObject = [[MyObject alloc] init]; //myObject retainCount = 1;

现在是不是有点晕, 我们先来把代码改一下, 官方的一种常见写法:

MyClass.h

@interface MyClass : NSObject {
    MyObject * _myObject;
}
@property (nonatomic, retain) MyObject *myObject;
@end

MyClass.m

@synthesize myObject = _myObject;

OK, 你现在再试下, 如果你用self._myObject = aMyObject; 或者 myObject = aMyObject; 你会得到一个错误, 为什么呢, 这里就是和Obj-c的存取方法有关了. 说白了很简单 , 大家都知道, @property (nonatomic, retain) MyObject *myObject; 是为一个属性设置存取方法, 只是平时我们用的方法名和属性名是一样的,现在你把它写成不同的名字, 就会很清楚了. _myObject是属性值本身, myObject则是存取方法名.

以下一次性给出assign retain和copy的setter方法:

// assign 
-(void)setMyObject:(id)newValue{
    _myObject = newValue; 
}
// retain 
-(void)setMyObject:(id)newValue{
    if (_myObject != newValue) { 
        [_myObject release]; 
        _myObject = [newValue retain]; 
    }  
}
// copy 
-(void)setMyObject:(id)newValue{
    if (_myObject != newValue) { 
        [_myObject release]; 
        _myObject = [newValue copy]; 
    } 
}

当在“=”左边调用self.myObject时是调用setter方法,

当在“=”右边调用self.myObject时是调用getter方法,

三、事例分析:

时间: 2024-10-13 23:12:04

对retain 和 assign的理解的相关文章

属性设置@property之retain,assign,weak,strong,copy

1.assign assign只是简单赋值,不更改索引计数,适用于基础数据类型 (例如NSInteger,CGFloat)和C数据类型(int, float, double, char, 等) 2.copy copy用来建立一个索引计数为1的对象,然后释放旧对象, 常用语NSString ,指在赋值时使用传入值的一份拷贝. 3.retain retain用来释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 对其他NSObject和其子类,对参数进行release旧值,再ret

IOS开发 strong,weak,retain,assign,copy nomatic 等的区别与作用

strong,weak,retain,assign,copy nomatic 等的区别 copy与retain:1.copy其实是建立了一个相同的对象,而retain不是:2.copy是内容拷贝,retain是指针拷贝:  3.copy是内容的拷贝 ,对于像NSString,的确是这样,但是如果copy的是一个NSArray呢?这时只是copy了指向array中相对应元素的指针.这便是所谓的"浅复制".4.copy的情况:NSString *newPt = [pt copy];此时会在

IOS内存管理retain,assign,copy,strong,weak

IOS内存管理retain,assign,copy,strong,weak IOS的对象都继承于NSObject, 该对象有一个方法:retainCount ,内存引用计数. 引用计数在很多技术都用到: window下的COM组件,多线程的信号量,读写锁,思想都一样. (一般情况下: 后面会讨论例外情况)alloc 对象分配后引用计数为1retain 对象的引用计数+1copy copy 一个对象变成新的对象(新内存地址) 引用计数为1 原来对象计数不变 release 对象引用计数-1 如果为

retain,copy,assign及autorelease ,strong,weak

一,retain, copy, assign区别 1. 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b.此时a 和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉. 2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference countin

retain, copy, assign区别

一.retain, copy, assign区别 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b.此时a 和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块 内存的时候会引起程序crash掉. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是

[转]strong,weak, retain, assign的区别

转自 http://lizhuang.iteye.com/blog/1989337 对Objective-C的对象变量属性不是很了解,就去找了一下这方面的文章,觉得这篇文章不错就转载了. strong与weak是由ARC新引入的对象变量属性 xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和assign,是不支持ARC的.xcode 4.3(ios5和以上版本)之后就有了ARC,并且开始使用 strong与weak assign: 用于非指针变量.用于 基础数

OC基础:内存(进阶):retain.copy.assign的实现原理

遍历构造器的内存管理 a.遍历构造器方法内部使用autorelease释放对象 b.通过遍历构造器生成的对象.不用释放. 内存的管理总结 1.想占用某个对象的时候,要让它的引用计数器+1(retain操作) 2.当不想再占用某个对象的时候,要让它的引用计数器-1(release操作) 3.谁alloc谁release,遍历构造器使用autorelease 另:当一个属性遵循了协议的时候(该属性就是代理),这时使用内存组的assign修饰. 多态:父类指针 指向 子类对象 没有继承就没有多态 父类

iOS 开发 property,strong,weak,retain,assign,copy,nomatic 的区别及使用

1:ARC环境下,strong代替retain.weak代替assign,xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和assign,是不支持ARC的.xcode 4.3(ios5和以上版本)之后就有了ARC,并且开始使用 strong与weak 2:weak的作用:在ARC环境下,所有指向这个对象的weak指针都将被置为nil.这个T特性很有用,相信很多开发者都被指针指向已释放的对象所造成的EXC_BAD_ACCESS困扰过,使用ARC以后,不论是str

strong,weak, retain, assign的区别

strong与weak是由ARC新引入的对象变量属性 xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和assign,是不支持ARC的.xcode 4.3(ios5和以上版本)之后就有了ARC,并且开始使用 strong与weak assign: 用于非指针变量.用于 基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id 如: @property (nonatomic, assign) i