看到了一篇文章的面試題,想了想如果自己回答的是會怎麼回答,發現還是忍不住要查百度,這裡就想總結總結面試題,靠自己的理論知識來解答,不斷完善,因為面試主要考的自己的思路,理論知識,總結是很有必要的。
1.為什麼說Objective-C是一門動態的語言?
動態語言指的是不需要在編譯時確定所有的東西,在執行時還可以動態的新增變數、方法和類,Objective-C 可以通過Runtime 這個執行時機制,在執行時動態的新增變數、方法、類等,所以說Objective-C 是一門動態的語言。Objective-C 使用的是 “訊息結構” 並非 “函式呼叫”:使用訊息結構的的語言,其執行時所應執行的程式碼由執行期決定;而使用函式呼叫的語言,則由編譯器決定。
延伸
因為在執行期可以繼續向類中新增方法,所以編譯器在編譯時還無法確定類中是否有某個方法的實現。對於類無法處理一個訊息就會觸發訊息轉發機制
訊息轉發分為兩大階段: “動態方法解析”:先徵詢接收者,所屬的類,能否動態新增方法,來處理這個訊息,若可以則結束,如不能則繼續往下走 “完整的訊息轉發機制”: 請接收者看看有沒其他物件能處理這條訊息,若有,就把這個訊息轉發給那個物件然後結束 執行時系統會把與訊息有關細節全部封裝到NSInvocation 物件中,再給物件最後一次機會,令其設法解決當前還未處理的這條訊息
2.講一下MVC和MVVM,MVP?
延伸
VIPER 現成框架
@property 後面可以有哪些修飾符?
1.執行緒安全的: atomic, nonatomic 2.訪問許可權的: readonly只讀, readwrite 讀寫 3.記憶體管理(ARC) assign,strong,weak,copy 4.記憶體管理(MRC)assign, retain,copy 5.指定方法名稱: setter= getter=
預設情況下,由編譯器合成的方法會通過鎖定機制確保其原子性(atomicity)。如果屬性具備nonatomic特質,則不使用同步鎖。
copy和mutableCopy,深複製和淺複製?
淺複製引用計數+1,深複製原物件引用計數不變。copy不可變物件相當於淺拷貝,copy可變物件,生成新物件。mutableCopy無論是可變還是不可變物件都是深拷貝。
什麼情況使用 weak 關鍵字,相比 assign 有什麼不同?
打破迴圈引用時候,比如delegate屬性。自身已經強引用了,也可以用weak,比如IBOutlet連出來的檢視設定成weak。 weak表明屬性定義了一種“非擁有關係”,為這種屬性設定新值,設定方法既不保留新值,也不釋放舊值。當屬性所指物件摧毀時,屬性也會清空nil。assign只針對於"純量型別"。assign可以用於非OC物件,weak必須用於OC物件。
block為什麼要用copy修飾?
在Objective-C中有三種block:
_NSConcreteGlobalBlock全域性靜態block,不會訪問外部區域性變數。
_NSConcreteStackBlock 儲存在棧中的block,當函式返回是被銷燬。
_NSConcreteMallocBlock儲存在堆中的block,當引用計數為0時被銷燬。
在MRC中,block是在棧區的,使用copy可以把它放到堆區,在ARC中寫不寫都行,因為系統自動copy了。對於block修飾copy和strong效果一樣的。
這個寫法會出什麼問題: @property (copy) NSMutableArray *array;
會有問題,因為NSMutaleArray copy之後是一個不可變物件,新增,刪除,修改陣列元素都會有問題。不寫nonatomic就是atomic,影響效能。
如何讓自己的類用 copy 修飾符?如何重寫帶 copy 關鍵字的 setter?
若想令自己寫的物件具有拷貝功能,則需要實現NSCopying協議。如果物件分為不可變和可變版本,則需要同時實現NSCopying和NSMutableCopying協議。 那麼怎麼讓類實現Copy呢? 類需要遵從NSCopying協議,實現copyWithZone方法。
-(id)copyWithZone:(NSZone *)zone {
Class *class = [[[self copy] allocWithZone:zone] init];
return class;
}
但在專案中可能沒這麼簡單,比如說類物件中的資料結構可能未在初始化方法中設定好。如果類中有一個可變陣列,那麼也需要把可變陣列拷貝過來。
-(id)copyWithZone:(NSZone *)zone {
Class *class = [[[self copy] allocWithZone:zone] init];
class -> array = [array mutaleCopy]; return class;
}
上面的方法不會逐個複製array中的元素,如果要深拷貝的話。 -(id)deepCopy {
Class *class = [[[self copy] allocWithZone:zone] init];
class->array = [[NSMutaleArray alloc] initWithArray:array]; return class;
}
重寫copy關鍵字的setter問題。
-(void)setName:(NSString *)name {
_name = [name copy];
}
如果屬性readonly,編譯器不會給它設定setter方法,我們用初始化設定好屬性初始值就不能再改變了。如何確保name被copy,在初始化方法中_name = [name copy];
@property 的本質是什麼?ivar、getter、setter 是如何生成並新增到這個類中的。
@property = ivar + getter + setter。
屬性有兩個概念:ivar(例項變數),存取方法(access method = getter + setter)。
"屬性"作為Objective-C的一項特性,主要作用在於封裝物件的資料。Objective-C物件通常會把其所需要的資料儲存為各種例項變數。例項變數一般通過存取方法來訪問的。其實就是“編譯器會自動寫出一套存取方法,用以訪問給定型別中具有給定名稱的變數。也可以說@property = getter + setter”。
第二個問題,如何新增到這個類的呢?
“自動合成(autosynthesis)”
完成屬性定義後,編譯器會自動編寫訪問這些屬性所需的方法,此過程叫“自動合成”。這個過程由編譯器在編譯期執行,所以在編譯器看不到原始碼。除了生成程式碼setter,getter之外,編譯器還要自動向類中新增適當型別的例項變數,並在屬性名前面加下劃線,以此作為例項變數的名字。也可以在類中通過程式碼@synthesize語法來指定例項變數的名字 例如 @synthesize property = _property;
我們每增加一個屬性,系統就會在ivar_list中新增一個成員變數的描述,在method_list中增加setter和getter方法的描述,在屬性列表中增加一個屬性的描述,然後就算該屬性在物件中的偏移量,然後給出setter和getter方法對應的實現,在setter方法中從偏移量的位置開始賦值,在getter方法中從偏移量開始取值,為了讀取正確位元組數,系統物件偏移量的指標型別進行了強轉。
@protocol 和 category 中如何使用 @property?
在protocol中使用@property只會生成setter和getter方法宣告,我們使用屬性的目的是希望遵守我們的物件能夠實現該屬性。
category使用@property也是隻會生成setter和getter方法宣告,如果要給category新增屬性的實現,需要藉助於objc_setAssociatedObject 和 objc_getAssociatedObject。
Runtime 如何實現 weak 屬性?
weak 表明屬性定義為一種“非擁有關係”。為這種屬性設定新值時,設定方法既不保留新值,也不釋放舊值。當屬性所指物件遭到摧毀時,屬性值也會清空(nil out)。
Runtime是如何實現weak變數自動置nil?
Runtime對註冊的類,會進行佈局,對於weak物件會放到hash表中。用weak指向的物件記憶體地址作為key,當此物件的引用計數為0的時候會dealloc,假如weak指向的物件記憶體地址是a,那麼就會以a為鍵,在這個weak表中搜尋,找到所有以a為鍵的weak物件,從而設定為nil。
@synthesize和@dynamic分別有什麼作用?
@property有兩個對應的詞,一個是@synthesize,一個是@dynamic,如果@synthesize和@dynamic都沒寫,那麼預設的是@synthesize var = _var;
@synthesize 是如果沒有手動實現setter方法和getter方法,那麼編譯器會自動加上這兩個方法。(系統預設有的)
@dynamic 告訴編譯器,不要自動生成setter和getter方法,由使用者自己實現。如果一個屬性被宣告為@dynamic var,然而並沒有提供@setter和@getter方法,編譯的時候沒問題,但當程式執行到instance.var = someVar,由於缺少setter導致程式崩潰,或者執行到someVar = var時,缺少getter方法崩潰。編譯時沒問題,執行時才執行相應的方法,這就是所謂的動態繫結。
用@property宣告的NSString(或NSArray,NSDictionary)經常使用copy關鍵字,為什麼?如果改用strong關鍵字,可能造成什麼問題?
因為父類指標可以指向子類物件,使用copy的目的是為了讓本物件的屬性不受外界影響。使用copy無論傳入的是可變還是不可變物件,我本身持有的都是不可變副本。
如果使用strong,那麼這個屬性就可能指向一個可變物件,那麼如果外部修改了,就會影響該屬性。
copy表達的所屬關係與strong類似。然而設定方法並不保留新值,而是將其拷貝。當屬性為NSString時,經常用此特質保護其封裝性,因為傳遞給設定方法的新值有可能指向一個NSMutableString類的例項。這個類是NSString的子類,表示一種可修改其值的字串,此時若是不拷貝字串,那麼設定完屬性之後,字串的值就可能在物件不知情的情況下被修改。所以,這是需要拷貝一份不可變的字串,確保物件中的字串不會無意間變動。只要實現屬性所用的物件是可變的,就應該在設定新屬性時拷貝一份。
在非集合類物件中,對不可變物件進行copy操作,是指標複製,mutableCopy操作時內容複製。對可變物件進行操作時copy和mutableCopy都是內容複製。所以,用@property宣告NSString,NSArray,NSDictionary經常使用copy關鍵字,因為他們有對應的可變型別。他們之間賦值操作,為確保物件中的字串值不會無意間變動,就應該在設定新屬性時拷貝一份。
@synthesize合成例項變數的規則是什麼?假如property名為foo,存在一個名為_foo的例項變數,那麼還會自動合成新變數麼?
例項變數 = 成員變數 = ivar
如果使用了屬性,那麼編譯器就會自動編寫訪問屬性所需的方法,此過程叫“自動合成”。這個過程由編譯器在編譯期執行,所以編譯器看不到方法。除了生成方法程式碼之外,編譯器還要自動向類中新增適當型別的例項變數,並在屬性名前面加下劃線,以此作為例項變數的名字。 也可以自己寫@synthesize 來指定生成的例項變數名稱。關於@synthesize:
1.如果指定了成員變數的名稱,就會生成指定名稱的成員變數。
2.如果成員已經存在則不再生成。
3.如果是@synthesize var;沒有指定成員變數的名稱會自動生成一個屬性同名的成員變數。
4.如果@synthesize var = _var,就不會生成成員變數了。
5.如果property名為var,還存在一個_var的例項變數,那麼不會自動合成新變數。
先寫到這裡,可以翻上去再鞏固一下。
下面是面試題二傳送門