[※]@property中有哪些屬性關鍵字?
原子屬性
atomic 和 nonatomic用來決定編譯器生成的getter和setter是否為原子操作,atomic 設置成員變量的@property屬性時 默認為是atomic 提供線程安全。
nonatomic 非原子性訪問對于屬性賦值的時候不加鎖,多線程并發訪問會提高性能,如果不加此屬性則默認是兩個訪問方法都為原子型事務訪問。
讀寫屬性
readonly 此標記說明屬性是只讀的
readwrite 此標記說明屬性會被當成讀寫的 這也是默認的屬性
內存管理語義
assign、strong、 weak、unsafe_unretained、copy
ARC 默認屬性
atomic、readwrite、strong(對象)/assign(基本數據)
[※]weak屬性需要在dealloc中置nil么?
不需要。
在ARC環境無論是強指針還是弱指針都無需在 dealloc 設置為 nil , ARC 會自動幫我們處理
即便是編譯器不幫我們做這些,weak也不需要在 dealloc 中置nil:
[※※※]@synthesize合成實例變量的規則是什么?假如property名為foo,存在一個名為_foo的實例變量,那么還會自動合成新變量么?
- 如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量,
- 如果這個成員已經存在了就不再生成了.
- 如果是 @synthesize foo;
還會生成一個名稱為foo的成員變量,也就是說:
如果沒有指定成員變量的名稱會自動生成一個屬性同名的成員變量, - 如果是 @synthesize foo = _foo;
就不會生成成員變量了.
[※※※※※]在有了自動合成屬性實例變量之后,@synthesize還有哪些使用場景?
- 同時重寫了setter和getter函數
- 重寫了只讀屬性property的getter(這里property必須聲明在.m文件中)
- 想要自定義實例變量的變量名
- 聲明在@protocol中的property
- 重載的屬性
備注:
重載屬性時最好使用@dynamic,雖然@synthesize也可以用
[※※]objc中向一個nil對象發送消息將會發生什么?
objc是動態語言,每個方法在運行時會被動態轉為消息發送,即:objc_msgSend(receiver, selector)。
objc在向一個對象發送消息時,
1.runtime庫會根據對象的isa指針找到該對象實際所屬的類,
2.然后在該類中的方法列表以及其父類方法列表中尋找方法運行,
3.然后在發送消息的時候,objc_msgSend方法不會返回值,所謂的返回內容都是具體調用時執行的。那么,回到本題,如果向一個nil對象發送消息,首先在尋找對象的isa指針時就是0地址返回了,所以不會出現任何錯誤。
如果給一個已經釋放的對象發送消息,會崩潰。
objc中向一個對象發送消息[obj foo]和objc_msgSend()函數之間有什么關系?
[obj foo];在objc動態編譯時,會被轉意為:objc_msgSend(obj, @selector(foo));
[※※※]什么時候會報unrecognized selector的異常?
objc在向一個對象發送消息時,runtime庫會根據對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,如果,在最頂層的父類中依然找不到相應的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX 。
objc的運行時會給出三次拯救程序崩潰的機會
Method resolution、Fast forwarding、Normal forwarding
[※※※※]一個objc對象的isa的指針指向什么?有什么作用?
[※※※※]下面的代碼輸出什么?
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
簡單來說,self和super都是指向當前實例的,不同的是,[self class]會在當前類的方法列表中去找class這個方法,[super class]會直接開始在當前類的父類中去找calss這個方法,兩者在找不到的時候,都會繼續向祖先類查詢class方法,最終到NSObject類。那么問題來了,由于我們在Father和Son中都沒有去重寫class這個方法,最終自然都會去執行NSObject中的class方法,結果也自然應該是一樣的。至于為什么是Son,我們可以看看NSObject中class的實現:
-(Class)class {
return object_getClass(self);
}
這就說的通了,返回的都是self的類型,self此處正好就是Son,因此結果就會輸出Son。
[※※※※]runtime如何通過selector找到對應的IMP地址?(分別考慮類方法和實例方法)
在尋找IMP的地址時,runtime提供了兩種方法
IMP class_getMethodImplementation(Class cls, SEL name); // 效率更高
IMP method_getImplementation(Method m)
1、IMP class_getMethodImplementation(Class cls, SEL name); // 效率更高
類方法(假設有一個類A)
class_getMethodImplementation(objc_getMetaClass("A"),@selector(methodName));
實例方法
class_getMethodImplementation([A class],@selector(methodName));
2、IMP method_getImplementation(Method m)
類方法
Method class_getClassMethod(Class cls, SEL name)
實例方法
Method class_getInstanceMethod(Class cls, SEL name)
[※※※※]使用runtime Associate方法關聯的對象,需要在主對象dealloc的時候釋放么?
- (void)setAddProperty:(id)addProperty {
objc_setAssociatedObject(self, @selector(addProperty), addProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)addProperty {
return objc_getAssociatedObject(self, @selector(addProperty));
}
- (void)dealloc {
[self setAddProperty:nil];
}
不需要,dealloc的時候會調用object_dispose,這兒會處理關聯對象,weak對象
[※※※※※]:objc中的類方法和實例方法有什么本質區別和聯系?
實例方法中可以使用類方法,用類名去調用
比如有一個類 example
里面定義 了兩個方法
+(void)fun1; //類方法
-(void)fun2; //實例方法
用法:
[example fun1];
example *tmp = [[example alloc]init];
[tmp fun2];
問題[※※※※※]:_objc_msgForward函數是做什么的,直接調用它將會發生什么?
直接調用_objc_msgForward是非常危險的事,如果用不好會直接導致程序Crash,但是如果用得好,能做很多非常酷的事。
一旦調用_objc_msgForward,將跳過查找 IMP 的過程,直接觸發“消息轉發”,如果調用了_objc_msgForward,即使這個對象確實已經實現了這個方法,你也會告訴objc_msgSend:“我沒有在這個對象里找到這個方法的實現”
runtime如何實現weak變量的自動置nil?
runtime 對注冊的類, 會進行布局,對于 weak 對象會放入一個 hash 表中。 用 weak 指向的對象內存地址作為 key,當此對象的引用計數為0的時候會 dealloc, 在這個 weak 表中搜索,找到所有以a為鍵的 weak 對象,從而設置為 nil。
weak 修飾的指針默認值是 nil (在Objective-C中向nil發送消息是安全的)
[※※※※※]:能否向編譯后得到的類中增加實例變量?能否向運行時創建的類中添加實例變量?為什么?
不能向編譯后得到的類中增加實例變量;
能向運行時創建的類中添加實例變量;
原因如下:
因為編譯后的類已經注冊在 runtime 中,類結構體中的 objc_ivar_list 實例變量的鏈表 和 instance_size 實例變量的內存大小已經確定,同時runtime 會調用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。所以不能向存在的類中添加實例變量;
運行時創建的類是可以添加實例變量,調用 class_addIvar 函數。但是得在調用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。
Runloop和線程的關系
runloop與線程是一一對應的,一個runloop對應一個核心的線程,為什么說是核心的,是因為runloop是可以嵌套的,但是核心的只能有一個,他們的關系保存在一個全局的字典里。
runloop是來管理線程的,當線程的runloop被開啟后,線程會在執行完任務后進入休眠狀態,有了任務就會被喚醒去執行任務。
runloop在第一次獲取時被創建,在線程結束時被銷毀。
對于主線程來說,runloop在程序一啟動就默認創建好了。
對于子線程來說,runloop是懶加載的,只有當我們使用的時候才會創建,所以在子線程用定時器要注意:確保子線程的runloop被創建,不然定時器不會回調。
//猜想runloop內部是如何實現的?
1、有一個判斷循環的條件,滿足條件,就一直循環
2、線程得到喚醒事件被喚醒,事件處理完畢以后,回到睡眠狀態,等待下次喚醒