杂笔,Objective-C的认知

杂笔Objective-C的认知

最近在为某讲解assign,copy,retain在属性的用法,发现自己理解了,却没有说明白,网上搜索了下,下列描述:

1. 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉。

2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以把它直接释放掉。

3. 上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。

4. copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。

5. atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果

再次补充:

@property是一个属性访问声明,扩号内支持以下几个属性:

1,getter=getterName,setter=setterName,设置setter与getter的方法名

2,readwrite,readonly,设置可供访问级别

2,assign,setter方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题

3,retain,setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序(CC上有相关资料)

4,copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。

5,nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。锁被加到所属对象实例级。

/***********************分割线******************************/

另外,在对UITextField.delegate赋值的时候,才发现此处声明:@property(nonatomic, assign) id<UITextFieldDelegate> delegate

搜索了下网上对UITextField和UITextFieldDelegate,看到以下地址对此的讨论

http://stackoverflow.com/questions/5176261/property-assign-and-retain-for-delegate

http://stackoverflow.com/questions/918698/why-are-objective-c-delegates-usually-given-the-property-assign-instead-of-retain

对此描述的问题是这样的

For iOS developer, delegate is used almost everywhere.

And seem like that we need use "assign" instead of retain for delegate like this

@property(assign) id delegate;

The reason is to avoid circular loop issue Why are Objective-C delegates usually given the property assign instead of retain?

I saw a lot codes , they still used "retain". So question here is to seek for a piece of codes to prove the circular loop issue if we use retain for delegate.

回答中的描述(用颜色区分下各个描述):

Retaining an object creates a strong reference, and an object cannot be deallocated until all of its strong references are released. If two objects retain each other, neither object ever gets deallocated because the connection between them cannot be broken

"The assign keyword will generate a setter which assigns the value to the instance variable directly, rather than copying or retaining it. This is best for primitive types like NSInteger and CGFloat, or objects you don't directly own, such as delegates."

The reason that you avoid retaining delegates is that you need to avoid a retain loop:

A creates B

A sets itself as B's delegate …

A is released by its owner

If B had retained A, A wouldn't be released, as B owns A, thus A's dealloc would never get called, causing both A and B to leak.

You shouldn't worry about A going away b/c it owns B and thus gets rid of it in dealloc.

Because the object sending the delegate messages does not own the delegate.

看到这里,简单理解了delegate使用assign关键字

在实际的应用,object.delegate = [[A alloc] init];//而不是[[[A alloc] init] autorelease]

2011-9-15,今天在实践NSXMLParser是看到delegate,以为又是属性,按照上述所说[[A alloc] init]方式处理,发现存在内存泄漏。

查阅官方资料才发现此处的delegate不是属性,是一个方法,对应setDelegeate才是设置委托的方法。故,应该使用[parser setDelegate:[[[A alloc] init] autorelease]];来自动释放此委托对象。

【PS】看来一个delegate的定义根据实际有区别,汗!注意注意

/***********************分割线******************************/

关于成员变量的访问属性:@private,@protected,@public

私密属性,成员函数访问

保护属性,成员函数访问或其子类成员函数访问

公开属性,所有访问

这里要注意一点:

成员变量使用->,属性@property使用.

针对@protected来说,其成员变量,如_thisprotected;

父类访问:self->_thisprotected;

子类访问:self->_thisprotected;

之所以这里提及@protected的访问,因为这个容易在子类写成super->_thisprotected或super._thisprotected