- @synthesize
@interface Test : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation Test
// 使用@synthesize必須先設(shè)置@property
// @synthesize name == @synthesize name = name
// 會(huì)自動(dòng)生成setter getter方法聲明和實(shí)現(xiàn)(可以都重寫) 并且生成對(duì)應(yīng)的成員變量怜浅,成員變量名就是后面的名字
// 像下面這么寫的話,默認(rèn)的_name成員變量就變成了syn_name谢床,通過self.name或syn_name來訪問
// 如果遵循的協(xié)議內(nèi)部有property烦味,就要用@synthesize
@synthesize name = syn_name;
- (void)setName:(NSString *)name {
syn_name = name;
}
- (NSString *)name {
return syn_name;
}
@end
- @dynamic
@interface Test : NSObject {
NSInteger _dynamic_height
}
@property (nonatomic, assign) NSInteger height;
@end
@implementation Test
// 使用@dynamic必須先設(shè)置@property
// 告訴編譯器不要生成成員變量礁鲁,也不要生成setter箍铭,getter的實(shí)現(xiàn),但是setter getter的方法聲明還是有
// 如果直接調(diào)用test.height = x 會(huì)報(bào)方法找不到
// 一般會(huì)再寫一個(gè)成員變量蜜唾,然后實(shí)現(xiàn)setter getter方法 杂曲,如_dynamic_height
// 不加成員變量也可以,實(shí)現(xiàn)方法就行
@dynamic height;
- (void)setHeight:(NSInteger)height {
_dynamic_height = height;
}
- (NSInteger)height {
return _dynamic_height;
}
@end
- @property
@property (nonatomic, assign) NSInteger height;
// 等同于@synthesize height = _height; 屬性是用來描述成員變量在當(dāng)前類中的特征
- nonatomic & atomic
// 源碼層面的區(qū)別
StripedMap<spinlock_t> PropertyLocks;
StripedMap<spinlock_t> StructLocks;
StripedMap<spinlock_t> CppObjectLocks;
#define MUTABLE_COPY 2
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
示例:
@interface Cat : NSObject
@property (nonatomic, copy) NSString *name;
@end
// 默認(rèn)cat.name = @"001"
@interface Person : NSObject
@property (nonatomic, strong) Cat *cat;
@end
1.threadA => 讀取cat.name
2.threadB => person.cat = Cat(@"002")
3.threadC => person.cat = Cat(@"003")
Q:threadA會(huì)讀取到什么值袁余?
Q:最后cat會(huì)是哪一個(gè)擎勘?
atomic:
1.讀取到的值有三種可能:"001","002"颖榜,"003"
2."002", "003"
nonatomic:
1.讀取到的值可能是"001"棚饵,"002","003"
或者報(bào)錯(cuò)掩完,why噪漾?
2."002", "003"
set方法偽代碼:
- (void)setCat:(Cat *)cat {
if (_cat != cat) {
// 1
[_cat release];
// 2
_cat = [cat retain];
// 3
}
}
在多線程環(huán)境中時(shí),如果threadA讀取值的時(shí)候且蓬,threadB剛好執(zhí)行到2欣硼,那么就有可能報(bào)錯(cuò)。
nonatomic atomic
兩者最大的區(qū)別就是atomic在操作的時(shí)候加了一個(gè)自旋鎖恶阴,使得同一時(shí)間只有一個(gè)線程能訪問setter/getter诈胜。但是這只能保證setter getter操作是完整的(指操作要么完成豹障,要么失敗)焦匈,并且返回一個(gè)有效的值(即操作原子性)血公。
在很多時(shí)候,多線程競爭同一資源缓熟,僅靠atomic是遠(yuǎn)遠(yuǎn)不夠的累魔,所以會(huì)采用其他的措施,如加鎖荚虚,信號(hào)量薛夜,串行隊(duì)列等籍茧,iOS上資源比較寶貴版述,所以推薦使用nonatomic,MacOS上就隨意了寞冯。
- 內(nèi)存管理關(guān)鍵字
strong
:ARC時(shí)代用來取代retain渴析,默認(rèn)局部變量、成員變量都是strong 對(duì)象引用計(jì)數(shù)會(huì)+1吮龄,持有對(duì)象
weak
:弱引用俭茧,不持有對(duì)象,不會(huì)增加對(duì)象的引用計(jì)數(shù)漓帚,當(dāng)指向的對(duì)象dealloc的時(shí)候會(huì)自動(dòng)置為nil母债,只能用于對(duì)象類型
assign
:同weak,但是assign不會(huì)置空尝抖,可能會(huì)有野指針的存在毡们,且assign可用于基本類型如 int float NSInteger等,因?yàn)榛绢愋投际窃跅昧辽?臻g由系統(tǒng)來管理內(nèi)存衙熔,所以用assign
retain
:持有對(duì)象 引用計(jì)數(shù)+1
copy
:setter時(shí),對(duì)新值進(jìn)行copy搅荞,如果生成了新對(duì)象红氯,那么原來對(duì)象的引用計(jì)數(shù)不會(huì)變,沒有生成新對(duì)象咕痛,那被copy對(duì)象引用計(jì)數(shù)+1痢甘。對(duì)象要遵守NSCopying協(xié)議,較多用在NSArray NSString上
unsafe_unretained
:有些類不支持weak修飾就用這個(gè)(可修飾基本數(shù)據(jù)類型)
- 默認(rèn)值
@property NSString *name;
@property NSInteger age;
//等同于
@property (atomic, strong, readwrite) NSString *name;
@property (atomic, assign, readwrite) NSInteger age;
// 對(duì)象類型 就是strong 基本類型就是assign
- 如果同時(shí)重寫setter和getter
編譯器會(huì)報(bào)錯(cuò)茉贡,它覺得你也不想要這個(gè)成員變量了产阱,加上@synthesize xxx 即可解決