@property相關
一、@property的本質是什么?ivar、getter、setter 是如何生成并添加到這個類中的?
(1)@property=實例變量(ivar)+存取方法(getter和setter);
(2)自動合成(autosynthesis)
二、@protocol協議和category類別中是如何使用@property
(1)只會生成setter和getter方法聲明;
(2)protocol中是希望遵守我協議的對象能實現該屬性;
(3)category需要使用關聯對象:objc_setAssociatedObject和objc_getAssociatedObject
三、@property中有哪些屬性關鍵字?
(1)原子性:nonatomic則不使用自旋鎖,默認是atomic由編譯器合成的方法會通過鎖定機制確保其原子性。
(atomic不是絕對的線程安全,其實無論是否是原子性的只是針對于getter和setter而言,下面有代碼例子)
(2)讀/寫權限:readwrite(讀寫)、readonly(只讀)
(3)內存管理屬性:assign、strong、weak、copy
(4)方法名:getter=<name> 、setter=<name>
例如@property (nonatomic, getter=isOn) BOOL on; BOOL一般命名為isXXX;
setter=<name>一般用在特殊的情境下 new、init開頭屬性,要重新命名。
另外也可以用關鍵字進行特殊說明,來避免編譯器報錯:
@property(nonatomic, readwrite, copy, null_resettable) NSString *initBy;
- (NSString *)initBy __attribute__((objc_method_family(none)));
(5)不常用的:nonnull(不能為空)、nullable(可以為空)、null_resettable(setter可為空, gette不可為空)
一、nonnull 表示不能為空
@property (nonnull, nonatomic, copy) NSString *name;//寫法一
@property (nonatomic, copy) NSString *__nonnull name;//寫法二,小寫時為兩個下劃線
@property (nonatomic, strong) NSString *_Nonnull name;//寫法三,大寫時為一個下劃線
- (void)test{
self.name = nil;//系統會有警告不能給這個屬性賦nil
// 這樣子不提示
NSString *string = nil;
self.name = string;//這里系統不會識別到
}
二、nullable 表示可以為空
@property (nullable, nonatomic, copy) NSString *name;//寫法一
@property (nonatomic, copy) NSString *__nullable name;//寫法二,小寫時為兩個下劃線
@property (nonatomic, strong) NSString *_Nullable name;//寫法三,大寫時為一個下劃線
三、null_resettable setter可為空, gette不可為空
setter方法是nullable(可以賦空值),getter方法是nonnull(取值不能為空)
當看到由null_resettable修飾的屬性時,就應該猜想這個屬性的初始化采用了懶加載方式
驗證atomic不是絕對的線程安全
@interface ViewController ()
@property (atomic , strong) NSString *info;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//A
dispatch_async(dispatch_get_global_queue(0, 0), ^{
while (1) {
self.info = @"a";
NSLog(@"A--info:%@", self.info);
}
});
//B
dispatch_async(dispatch_get_global_queue(0, 0), ^{
while (1) {
self.info = @"b";
NSLog(@"B--info:%@", self.info);
}
});
// 根據線程安全定義,如果atomic為線程安全A輸出應該永遠為A--info:a,B輸出應該永遠為B--info:b
// NSlog會有:A--info:b
}
@end
四、@syncthesize和@dynamic分別有什么作用?
(1)都是@property對應的詞,默認是@syncthesize var=_var;
(2)@syncthesize:編譯器自動實現getter、setter方法;
(3)@dynamic是告訴編譯器,getter、setter方法由用戶自己實現,不自動生成。
@synthesize 合成實例變量(隱藏創建一個_xxx)的規則,有以下幾點:
(1)如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量,
(2)如果這個成員已經存在了就不再生成了.
(3)如果是 @synthesize foo; 會生成一個名稱為foo的成員變量.
(4)默認是@syncthesize var=_var;
默認不寫@syncthesize,是自動合成,如果不寫@syncthesize,一下幾種情況也不自動合成實例變量(隱藏創建一個_xxx)
(1)同時重寫了 setter 和 getter 時
(2)重寫了只讀屬性的 getter 時
(3)使用了 @dynamic 時
(4)在 @protocol 中定義的所有屬性
(5)在 category 中定義的所有屬性
(6)重載的屬性
五、ARC下,默認的屬性修飾是什么?
(1)基本數據類型的是:atomic,readwrite,assign
(2)OC對象的是:atomic,readwrite,strong
六.什么情況使用weak關鍵字?與assign有什么不同?
(1)在ARC中,可能出現循環引用的時候,需要一段設置weak來解決,比如:delegate屬性的修飾。
(2)不同點:weak修飾屬性,弱引用,不會保留新值,也不會釋放舊值,如果舊值被摧毀這個屬性賦值nil,繼續使用不會閃退App。
assign 可以用非 OC 對象( CGFloat 或 NSlnteger 等),而 weak 必須用于 OC 對象,原因是assign修飾的對象被釋放后,指針的地址依然存在,造成野指針,在堆上容易造成崩潰。而棧上的內存系統會自動處理,不會造成野指針。
strong、assign、weak、copy等關鍵相關
七、copy相關
1、怎么用copy關鍵字?
(1)NSString、NSArray、NSDictionry等經常使用copy,因為他們有可變的,如果修飾strong把可變的賦值他們,他們會變成可變,為確保不會無意變動應該使用copy修飾;
(2)Block在ARC下 賦值就是copy,棧復制到堆上;
(3)copy出來的東西是不可變的,mutableCopy出來的東西是可變的
源對象類型 | 拷貝方法 | 副本對象類型 | 是否產生新對象 | 拷貝類型 |
---|---|---|---|---|
NS* | copy | NS* | 否 | 淺拷貝 |
NS* | mutableCopy | NSMutable* | 是 | 深拷貝 |
NSMutable* | copy | NS* | 是 | 深拷貝 |
NSMutable* | mutableCopy | NSMutable* | 是 | 深拷貝 |
注:淺拷貝 == 指針拷貝;深拷貝 == 內容拷貝,深復制需要實現NSCoding協議,實現- (void)copyWithZone:(NSZone *)zone方法
2、父類實現深拷貝時,子類如何實現深度拷貝?
(1)Person的copyWithZone里調用Person *p = [[[self class] alloc] init];
(2)Son的copyWithZone里調用Son *s = [super copyWithZone:zone];
(3)配置Son的屬性
@implementation Person
- (id)copyWithZone:(NSZone *)zone
{
Person *p = [[[self class] alloc] init];
p. personId = self.personId;
return p;
}
@end
@implementation Son
- (id)copyWithZone:(NSZone *)zone
{
Son *s = [super copyWithZone:zone];
s.studentId = self.studentId;
return s;
}
@end
3、父類沒有實現深拷貝時,子類如何實現深度拷貝?
(1)Son的copyWithZone里調用Son *s = [[[self class] alloc] init];
(2)配置Person屬性、配置Son的屬性
@implementation Son
- (id)copyWithZone:(NSZone *)zone
{
Son *s = [[[self class] alloc] init];
s.personId = self. personId;
s.studentId = self.studentId;
return s;
}
@end
4、這個寫法會出什么問題: @property (copy) NSMutableArray *array;?
(1)copy出來的對象是不可變的,這個array如果操作add、rem、ins,會崩潰;
(2)使用atomic(默認)原子性線程鎖會影響性能。 nonatomic沒有線程鎖。