前言:我是參考 南峰子 的博客加上自己理解寫的,原著專輯大家自己可看:http://southpeak.github.io/categories/objectivec/
一、 先說說屬性(property)和成員變量 (instance var(Ivar))的區(qū)別
其實主觀上,自己認(rèn)為:屬性就是我們平時在.h中用@property關(guān)鍵字聲明的東西,而實例變量是我們在.h或.m中用{}聲明的東西。
@interface ViewController : UIViewController{
NSInteger integer1; //實例變量
}
@property (assign,nonatomic) NSInteger integer2; //實例屬性
- 一般我們在使用
@property聲明的屬性,如果沒在.m文件中使用@synthesize同步的話,系統(tǒng)會默認(rèn)生成一個與屬性對應(yīng)的實例變量。如上面的代碼,我們在.m中可以直接通過訪問_integer2。如果使用在.m文件中使用@synthesize同步的話,如:@synthesize integer2,那么屬性對應(yīng)的成員變量就不是_integer2,而是integer2,就得到一個和屬性名稱一樣的實例變量。當(dāng)然@synthesize語句也可以用戶指定當(dāng)前屬性和那個成員變量綁定,如@synthesize integer2 = integer1,這樣寫就制定了屬性integer2和實例變量integer1綁定了。 - 在我們使用
self.integer2,因為integer2是通過使用@property來聲明的屬性,我們使用的時候一般是通過self.來使用,其實是系統(tǒng)分裝的setter 和 getter方法,我們看是通過一個小點.訪問屬性,其實執(zhí)行是方法(據(jù)說這是當(dāng)時OC設(shè)計者估計和Java學(xué)的),通過方法去給對應(yīng)的實例變量(_integer2)讀取賦值的。為什么這樣做了,其實是我們讀取寫入的時候會更具我們跟在@property后面括號(assign,nonatomic)聲明的關(guān)鍵字去管理實例變量的內(nèi)存,如retain,copy等。 - 如果我們直接訪問實例變量可以通過直接調(diào)用實例變量的名字或通過
self->實例變量名字訪問,這時候的內(nèi)存管理方式我們沒有指定,其實就是直接賦值(assign),而屬性可以通過修飾詞加上getter和setter方法實現(xiàn)豐富的內(nèi)存管理方式。
PS:以前碰到一個小問題http://www.itdecent.cn/p/ded24cade177可以直觀的解釋
二、修飾符
逃也逃不掉,該弄懂的還是要弄的
1.原子性(Atomicity)包含:nonatomic;
2.讀寫屬性(Writability)包含:readwrite / readonly;
3.setter語義(Setter Semantics)包含:assign / retain / copy;
1. 原子性:
nonatomic:非原子性訪問,不加同步,多線程并發(fā)訪問會提高性能。如果不加此屬性,則默認(rèn)是兩個訪問方法都為原子型事務(wù)訪問。默認(rèn)值是atomic,為原子操作。(atomic是Objc使用的一種線程保護(hù)技術(shù),基本上來講,是防止在寫未完成的時候被另外一個線程讀取,造成數(shù)據(jù)錯誤。而這種機制是耗費系統(tǒng)資源的,所以在iPhone這種小型設(shè)備上,如果沒有使用多線程間的通訊編程,那么nonatomic是一個非常好的選擇。)
2. 讀寫屬性
readwrite / readonly:決定是否生成set訪問器,readwrite是默認(rèn)屬性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。readonly關(guān)鍵字代表setter不會被生成, 所以它不可以和 copy/retain/assign組合使用。
注意:readwrite/readonly配合使用:屬性在外部是只讀,自己使用時讀寫使用self->實例變量直接讀或?qū)?/p>
3. setter語義
這些屬性用于指定set訪問器的語義,也就是說,這些屬性決定了以何種方式對數(shù)據(jù)成員賦予新值。
--assign:直接賦值,索引計數(shù)不改變,適用于簡單數(shù)據(jù)類型,例如:NSIngeter、CGFloat、int、char等。
--retain(strong):指針的拷貝,使用的是原來的內(nèi)存空間。對象的索引計數(shù)加1。此屬性只能用于Objective-C對象類型,而不能用于Core Foundation對象。(原因很明顯,retain會增加對象的引用計數(shù),而基本數(shù)據(jù)類型或者Core Foundation對象都沒有引用計數(shù))。
--copy:對象的拷貝,新申請一塊內(nèi)存空間,并把原始內(nèi)容復(fù)制到那片空間。新對象的索引計數(shù)為1。此屬性只對那些實行了NSCopying協(xié)議的對象類型有效。
- 很多Objective-C中的object最好使用用retain(strong),一些特別的object(例如:string)使用copy。
三、實例變量 和 屬性在RunTime中關(guān)聯(lián)的方法
實例變量: 英文Instance var 簡寫:Ivar,在OC中也是使用結(jié)構(gòu)體objc_ivar定義一個Ivar,其結(jié)構(gòu)體定義如下:
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
關(guān)于成員變量的一些方法:
/** 獲取成員變量名 */
OBJC_EXPORT const char *ivar_getName(Ivar v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
/**獲取成員變量類型編碼 */
OBJC_EXPORT const char *ivar_getTypeEncoding(Ivar v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
/** 獲取成員變量的偏移量 */
OBJC_EXPORT ptrdiff_t ivar_getOffset(Ivar v)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
對于類型id或其它對象類型的實例變量,可以調(diào)用object_getIvar
和object_setIvar來直接訪問成員變量,而不使用偏移量
屬性: property ,在OC中使用結(jié)構(gòu)體objc_property定義objc_property_t表示屬性(我沒有找到objc_property結(jié)構(gòu)體的具體聲明)。另外,OC中使用結(jié)構(gòu)體objc_property_attribute_t定義一個屬性的描述信息,它的定義如下:
/// Defines a property attribute
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
屬性常用的方法:
// 獲取屬性名
const char * property_getName ( objc_property_t property );
// 獲取屬性特性描述字符串
const char * property_getAttributes ( objc_property_t property );
// 獲取屬性中指定的特性
char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );
// 獲取屬性的特性列表
objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount )1