1.風格糾錯題
typedef enum {
UserSexMan,
UserSexWoman
}UserSex;
@interface UserModel : NSObject
@property(nonatomic,strong) NSString *name;
@property(nonatomic,assign) int age;
@property(nonatomic,assign) UserSex sex;
- (instancetype)initModelWithUserName:(NSString *)name WithAge:(NSUInteger)age;
- (void)doLogIn;
@end複製程式碼
答案:
typedef NS_ENUM(NSInteger,UserSex) {
UserSexMan,
UserSexWoman
};
//1.eunm應該替換為NS_OPTIONS或NS_ENUM
@interface UserModel : NSObject
@property(nonatomic,copy) NSString *name;
//2.strong應該改為copy
@property(nonatomic,assign) NSUInteger age;
//3.int應該改為NSUInteger
@property(nonatomic,assign) UserSex sex;
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(UserSex)sex;
//4.指定初始化方法應該包含所有引數
+ (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(UserSex)sex;
//5.應該寫一個類方法來初始化
- (void)logIn;
//6.命名規範
@end
複製程式碼
2.什麼時間使用weak關鍵字,相比assign有什麼不同
1.什麼情況使用weak
- 在ARC下,為了防止迴圈引用,比如設定delegate的時候
- 自身已經對它進行一次強引用,沒必要再強引用一次的時候,比如自定義IBOutLet控制元件屬性一般也用weak(也可用strong)。
2.不同
- weak和assign一樣都表示一種賦值關係,既不保留新值,也不釋放舊制,但是weak屬性所指的物件被銷燬時,指標會自動置為nil。
- weak必須用於OC物件,而assign可以用於基本資料型別(非OC物件)
3.怎麼用copy關鍵字
用途:
- NSString,NSArray,NSDictionary等等經常使用copy關鍵字,是因為它們有對應的可變型別NSMutableString,NSMutableArray,NSMutableDictionary;
- block也經常用copy關鍵字
原因:
- copy此特質所表達的所屬關係和strong類似,然而設定方法並不保留新值,而是將其拷貝,當所屬型別為NSString時,經常用此特質來保護其封裝性,因為傳遞給設定方法的新值有可能指向NSMutableString型別的例項,此時若是不拷貝例項,那麼設定完屬性之後,字串的值可能在物件不知情的情況下被人修改,所以,這時應該拷貝一份不可變的NSString,確保物件中的字串不會無意間被改動。
- block使用copy是從MRC遺留下來的傳統,在MRC中,方法內部的block是在棧區的,使用copy可以把它拷貝到堆區,在ARC中寫不寫都行,對用block使用copy和strong都是一樣的。
4.這個寫法會出什麼問題@property (copy) NSMutableArray *array;
- 對陣列進行增刪改的時候,程式會因為找不到對應的方法而崩潰,因為copy就是複製一個不可變陣列的物件。
- 使用了atomic會嚴重影響效能。並且atomic並不能保證執行緒安全,atomic為屬性的set,get方法就鎖,保證了屬性被訪問時的執行緒安全,但是屬性所指向的物件仍然可以同時被多個執行緒同時訪問,所以atomic並不能保證執行緒安全,通常在開發iOS程式是,一般會用nonatimic屬性。
5.如何讓自己的類用copy修飾符,如何重寫帶copy關鍵字的setter?
1.讓自己的類支援NSCopying協議
- 宣告該類遵從NSCopying協議
- 實現 NSCopying 協議。該協議只有一個方法:- (id)copyWithZone:(NSZone *)zone;
2.如何重寫帶 copy 關鍵字的 setter***方法
- (void)setName:(NSString *)name {
//[_name release];
_name = [name copy];
}複製程式碼
6.@property的本質是什麼,ivar,set,get是如何生成並新增到這個類中的
@property 的本質是什麼?
@property = ivar + set + get複製程式碼
ivar,set,get是如何生成並新增到這個類中的
完成屬性定義後,編譯器會編寫訪問這些屬性所需的方法,此過程叫做自動合成。這個過程由編譯器在編譯器完成,所以在編譯器裡看不到合成方法的原始碼。除了生成set,get方法外,編譯器還要自動向類中新增適當型別的例項變數,並且在屬性名前面加下劃線,一次作為例項變數的名稱。此外,也可以在類的實現程式碼中通過@synthesize語法來制定例項變數的名字。
複製程式碼
7.@protocol和category中如何使用@property
- 在@protocol中宣告屬性,只會生成對應的set,get方法宣告,我們使用屬性的目的,是為了讓遵循改協議的物件能實現該屬性。
- category 使用 @property 也是隻會生成 setter 和 getter 方法的宣告,如果我們真的需要給 category 增加屬性的實現,需要藉助於執行時的兩個函式:
- objc_setAssociatedObject()
- objc_getAssociatedObject()
8.runtime如何實現weak屬性
1.weak屬性的特點:
weak此特質表明該屬性定義了一種“非擁有關係”,為這種屬性設定新值時,設定方法既不保留新值,也不釋放舊值,此特質與assign類似,然而當屬性所指的物件被銷燬時,屬性值也會置空。2.runtime如何實現weak的自動置空:
runtime對註冊的類會進行佈局,對於weak物件會放入一個hash表中。用weak所指向的物件記憶體地址為key,當此物件的引用計數為0時會dealloc,嫁入weak指向的記憶體地址為a,那麼就以a為鍵,找到所有以a為鍵的物件,從而設定為nil。
9.@property都有哪些修飾符
屬性可以擁有的特質分為四類
- 原子性:nonatomic和atomic
- 讀寫許可權:weak,assign,strong,copy,retain,unsafe_unretained
- 記憶體管理語義,readwrite,readonly
- set,get方法
10.weak屬性需要在dealloc中置nil麼?
不需要,在屬性所指的物件被銷燬是,屬性值也會置空。
11.@synthesizer和@dynamic有什麼作用
- @synthesize語義是告訴編譯器如果你沒有手動實現set,get方法,那麼編譯器會自動為你加上這兩個方法。
- @dynamic語義是告訴編譯器不要自動合成set,get方法,這兩個方法會由使用者手動實現。但如果你沒有實現set,get方法,編譯的時候不會報錯,執行時一旦訪問這兩個方法,程式就會崩潰。
12.ARC下,不顯式指定屬性關鍵字時,預設的關鍵字有哪些?
- OC物件:atomic readwrite strong
- 基本資料型別(非OC物件): atomic readwrite assign
13.NSString用copy關鍵字描述,而不用strong描述的原因
- 因為父類指標可以指向子類物件,使用copy的原因是為了讓本物件的屬性不受外界影響,使用copy無論給我傳入一個可變物件還是不可變物件,我本身持有的都是一個 不可變的副本。
- 如果我們使用strong,屬性就可能指向一個可變物件,如果這個可變物件在外界被修改了,屬性也會受到影響。
14.@synthesize合成例項變數的規則是什麼?假如property名為foo,存在一個名為_foo的例項變數,那麼還會自動合成新變數麼?
例項變數 = 成員變數 = ivar
- 如果@synthesize指定了例項變數的名稱,那麼就會生成一個指定名稱的成員變數
- 如果沒有使用@synthesize指定,那麼已經存在了_foo的例項變數,就不會再生成了
15. 在有了自動合成屬性例項變數之後,@synthesize還有哪些使用場景?
- 同時重寫了set和get方法
- 重寫了只讀屬性的get方法
- 使用@dynamic
- 在@protocol中定義的屬性
- 在category中定義的屬性
- 過載了父類的屬性
這些情況下都需要你使用@synthesize手動合成ivar,另外還可以用來更改屬性對應的成員變數的名稱。
16. objc中向一個nil物件傳送訊息將會發生什麼?
如果向一個nil物件傳送訊息,首先在尋找物件的isa指標時就是0地址返回了,所以不會出現任何錯誤。
17.objc中向一個物件傳送訊息[obj foo]和objc_msgSend()函式之間有什麼關係?
該方法編譯之後就是objc_msgSend()
函式呼叫.
18. 什麼時候會報unrecognized selector的異常?
走完訊息傳遞的流程和訊息轉發的流程都找不到對應的方法時就會報unrecognized selector的異常
訊息傳遞的流程:
- 根據物件的isa指標找到物件所屬的類,在類的cache中找SEL對應的方法,如果找到就去實現,找不到走下一步
- 在類的方法列表中找,找到就去實現,並把方法就如到cache中,找不到走下一步
- 在類的父類方法列表中找,一直到NSObject類為止,如果能找到就去實現,找不到就走訊息轉發的流程
訊息轉發的流程:
- objc執行時會呼叫
+resolveInstanceMethod:
或者+resolveClassMethod:讓你動態新增方法實現
-forwardingTargetForSelector:將訊息轉發給備援接受者
首先它會傳送-methodSignatureForSelector訊息獲得函式的引數和返回值型別。如果methodSignatureForSelector返回nil,Runtime則會發出doesNotRecognizeSelector訊息,程式這時也就掛掉了。如果返回了一個函式簽名,Runtime就會建立一個NSInvocation物件併傳送forwardInvocation訊息給目標物件,如果forwardInvocation返回nil,這時也會報doesNotRecognizeSelector異常。
19. 一個objc物件如何進行記憶體佈局?(考慮有父類的情況)
- OC物件的結構圖
- isa指標
- 根類的例項變數
- 倒數第二層父類的例項變數
- 。。。。。。
- 父類的例項變數
- 類的例項變數
20.一個objc物件的isa指標指向什麼,起什麼作用?
指向它的類物件,從而找到類物件上的方法
21.下面的程式碼輸出什麼
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end複製程式碼
Son,Son
22. runtime如何通過selector找到對應的IMP地址?
每一個類物件中都有一個方法列表,方法列表中記載著方法的名稱,實現以及引數型別,其實selector本質就是方法名稱,通過這個名稱在方法列表中就可以找到對應的方法實現。
23. 使用runtime Associate方法關聯的物件,需要在主物件dealloc的時候釋放麼?
無論在MRC下還是ARC下均不需要。
24. objc中的類方法和例項方法有什麼本質區別和聯絡?
類方法
- 類方法是屬於類物件的
- 類方法只能通過類物件呼叫
- 類方法中的self是類物件
- 類方法可以呼叫其他的類方法
- 類方法中不能訪問成員變數
- 類方法中不能直接呼叫物件方法
例項方法
- 例項方法是屬於例項物件的
- 例項方法只能通過例項物件呼叫
- 例項方法中的self是例項物件
- 例項方法中可以訪問成員變數
- 例項方法中直接呼叫例項方法
- 例項方法中也可以呼叫類方法(通過類名)