上次我們說到了構造方法,書接上文,這次我們來詳細了解一下OC中@property中的內容.
本文也是我自己尋找了相關的資料自己整理出來的,如有出錯或者不足的地方,請及時留言溝通!相互進步~
1.@Property
@property:是OC中聲明屬性的語法,它可以快速方便的為實例變量創建存儲器,并允許我們通過點語法來使用存儲器.
存儲器(accessor): 指用于獲取和設置實例變量的方法。用于獲取實例變量值的存取器是getter,用于設置實例變量值的存取器是setter。
下面的代碼就是我們一開始學習OC一般都要寫的內容:
//Student.h文件
@interface Student : NSObject
{
NSString *_name;
int age;
}
//name實例變量的setter方法的聲明
-(void)setName:(NSString *)newName;
//name實例變量的getter方法的聲明
-(NSString *)name;
//下面同理
//setter
-(void)setAge:(int)newAge;
//getter
-(int)age;
@end
上面的代碼中name和age就是Student的實例變量,并且可以看到分別對這兩個實例變量聲明了get/set方法,即存取器
//Student.m文件
import "Student.h"
@implementation Student
//name實例變量的setter方法實現
- (void)setName:(NSString *)newName{
_name = newName;
}
//name實例變量的getter方法實現
- (NSString *)name{
return _name;
}
//下面同理
- (void)setAge:(int)newAge{
age = newAge;
}
- (int)age{
return age;
}
@end
//main.m文件
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *s1 = [[Student alloc]init];
s1.age = 18;
s1.name = @"小明";
NSLog(@"學生的姓名:%@,年齡:%d",s1.name,s1.age);
}
return 0;
}
輸出結果: property[16506:727833] 學生的姓名:小明,年齡:18
上面我們說過,使用@property的作用就是讓系統為我們自動生成set和get方法,省去了程序員的代碼量.
下面我們使用@property來試一下:
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)int age;
-(void)showInfo;
@end
這里我們在.h文件直接用@property生成了name和age和一個展示信息的方法,然后下面的圖片就展示了系統為我們自動生成的setter和getter方法
很清晰明了了, 然后我們在Student.m文件中實現一下我們自己寫的展示信息的方法:
#import "Student.h"
@implementation Student
- (void)showInfo{
NSLog(@"學生的姓名:%@,年齡:%d",_name,_age);
}
@end
//main.m文件中實例化對象 然后賦值 調用方法
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *s1 = [[Student alloc]init];
s1.age = 18;
s1.name = @"小明";
[s1 showInfo];
}
return 0;
}
輸出結果:property[16506:727833] 學生的姓名:小明,年齡:18
2.@property的特性
和很多剛開始學習OC的同學們一樣.看OC代碼一直很糾結這個@property后面跟著的括號里放的到底是些什么鬼東西...神煩!
尤其是作為程序員,遇到不會的東西在搞明白之前,根本不敢用啊!心里沒底!所以就花了些時間把@property的特性研究了下
@property(nonatomic,readonly,copy)NSString *name;
@property(nonatomic,readwrite,assign)int age;
我們可以把上面圓括號里的東西分為三類,分別是: 原子性 、讀寫權限、內存管理
2.1 原子性
atomic(默認): atomic意為操作是原子的,意味著只有一個線程訪問實例變量。atomic是線程安全的,至少在當前的存取器上是安全的。它是一個默認的特性,但是很少使用,因為比較影響效率,這跟ARM平臺和內部鎖機制有關。
nonatomic: nonatomic跟atomic剛好相反。表示非原子的,可以被多個線程訪問。它的效率比atomic快。但不能保證在多線程環境下的安全性,在單線程和明確只有一個線程訪問的情況下廣泛使用
2.2 讀寫權限
readwrite(默認):readwrite是默認值,表示該屬性同時擁有setter方法和getter方法。
readonly: readonly表示只有getter方法沒有setter方法。
2.3內存管理
- assign(默認): 用于值類型,如int、float、double和NSInteger,CGFloat等表示單純的復制. 可用于MRC/ARC環境中. 我的經驗就是聲明實例變量的時候不帶*號的統統用assign,還包括不存在所有權關系的對象,比如常見的delegate
@property(nonatomic) int running;
@property(nonatomic,assign) int running;
以上兩行代碼的意思是相同的
- retain: 在setter方法中,需要對傳入的對象進行引用計數加1的操作。簡單來說,就是對傳入的對象擁有所有權,只要對該對象擁有所有權,該對象就不會被釋放.
-(void)setName:(NSString*)_name{
//首先判斷是否與舊對象一致,如果不一致進行賦值。
//因為如果是一個對象的話,進行if內的代碼會造成一個極端的情況:當此name的retain為1時,使此次的set操作讓實例name提前釋放,而達不到賦值目的。
if ( name != _name){
[name release];
name = [_name retain];
}
}
千萬注意下面!!
在MRC運行環境下, retain參數生成的setter方法為標準的MRC內存管理代碼,不會自動的在dealloc中生成release代碼
//setter方法為標準的MRC內存管理代碼:
-(void)setTeacher:(Teacher *)teacher{
if(_teacher != teacher){ //判斷新舊對象是否是同一個對象
[_teacher release]; //如果不是,就release舊的
_teacher = [teacher retain]; //去retain新的 再賦值
}
}
所以我們要手動的在dealloc中release:
//xxx.h文件
@property(nonatomic,retain)Student *student;
//xxx.m文件
- (void)dealloc
{
[self.teacher release];
[super dealloc];
}
copy: 當屬性是NSString數據類型的時候就使用copy,copy此特質所表達的所屬關系與strong類似。然而設置方法并不保留新值,而是將其“拷貝”
strong: strong是在iOS引入ARC的時候引入的關鍵字,是retain的一個可選的替代
表示實例變量對傳入的對象要有所有權關系,即強引用. strong跟retain的意思相同并產生相同的代碼, 但是語意上更好更能體現對象的關系weak: 在setter方法中,需要對傳入的對象不進行引用計數加1的操作.
簡單來說,就是對傳入的對象沒有所有權,當該對象引用計數為0時,即該對象被釋放后,用weak聲明的實例變量指向nil, 即實例變量的值為0.
總結:
今后寫OC的代碼,一般都使用@property聲明,可以讓系統自動為我們生成setter和getter方法.
一般聲明delegate的時候用weak比較多
取代了之前的assign,因為使用weak時: 防止循環引用. 對象銷毀之后會自動置為nil,防止野指針; assign不能自動置為nil,需要手動在dealloc方法的實現中將retain的對象置為nil
特殊情況是: 希望在dealloc中調用delegate的某些方法進行釋放,此時如果使用weak將引起異常,因為此時已經是nil了,那么采用assign更為合適retain與copy
copy是內容拷貝 , 例如NSString,但是如果copy的是一個NSArray呢?這時只是copy了指向array中相對應元素的指針.這便是所謂的"淺復制".
retain是指針拷貝, 記得retain之后要release!weak 和 strong 屬性只有在你打開ARC時才會被要求使用,這時你是不能使用retain release autorelease 操作的,因為ARC會自動為你做好這些操作,但是你需要在對象屬性上使用weak 和strong,其中strong就相當于retain屬性,而weak相當于assign。
本文中的一部分內容摘自以下地址:
博客園: iCocos
cocoaChina: 子龍山人 Dev talking