設計模式,,,一個程式猿應一生追求完美的東西

kaihaOS發表於2016-04-06
描述一下KVO和KVC。
Key-Value Observing (簡寫為KVO):當指定的物件的屬性被修改了,允許物件接受到通知的機制。每次指定的被觀察物件的屬性被修改的時候,KVO都會自動的去通知相應的觀察者。
KVC是KeyValue Coding的簡稱,它是一種可以直接通過字串的名字(key)來訪問類屬性的機制。而不是通過呼叫Setter、Getter方法訪問。
 
3簡述NotificationCenter、KVC、KVO、Delegate?並說明它們之間的區別?
答:訊息中心,訊息通知;
      利用鍵-值間接訪問類中的某個屬性
      利用鍵-路徑間接訪問類中的某個屬性,也稱觀察者模式
      代理,多用於兩個類之間的傳值
15.你熟悉的設計模式有哪些,請說說對他們的理解。
答:單例,通知,KVO,代理,target-action等
單例,主要特點是一個類只有一個物件。對外提供了一個獲取唯一物件的方法,一般都是類方法,完整的單例會重寫很多引用計數相關的方法(比如:allocWithZone,copyWithZone,retain,release,autorelease,retainCount等)以保證物件在任何情況下都唯一。單例最大的價值就是建立程式級別的全域性變數,就是把不同模組都要用的變數以屬性的形式放到單例裡面,以便隨時使用。音訊播放類程式一般會寫單例來管理需要播放的音樂資訊,需要下載的地方也會以單例的形式來管理下載物件。
通知,是M與C通訊的方式之一。一般是Model傳送變化的時候,會傳送通知告訴Controller,Controller再做相應的處理。需要先往通知中心裡面註冊觀察者,然後在合適的時機,通知中心post通知,觀察者做對應的處理,當觀察者將要釋放的時候,從通知中心移除觀察者。
KVO,也是M與C通訊的方式。一般是C去觀察M的某個屬性,某個屬性發生變化之後,C做出相應的處理,當C將要釋放的時候,M移除觀察者。
代理,是V與C通訊的方式之一。一般C是V的代理,V發生變化的時候,C做對應的調整。例如:UITableView被點選了,由Controller做處理。我們在自己寫代理的時候,一定要清楚誰來處理事件,誰來呼叫代理方法。通常情況下都是C處理時間,V在適當的時候呼叫代理方法。
target-action,也是V與C通訊的方式之一。一般C是V的target,V被點選或者被滑動之後,C做出對應的處理。無論是target-action還是代理,核心都是回撥。
 
8.在使用系統的一些類例如UITableView時,會發現其delegate屬性的語義設定為assign而不是retain,為什麼呢?
答:delegate 的語義修飾符 為assign 不是 retain 主要是為了避免兩個物件因相互引用造成的記憶體洩露問題。
因為  retain修飾delegate,當通過set方法賦值時,物件的引用計數會+1.
如果此時兩個物件具有如下關係:A物件有一個屬性是B,B的delegate是A。即互相為彼此的屬性。例如: A 是viewController ,B是tableView.  B 是A的屬性,B的引用計數會+1,B的delegate是A,A 的引用計數也會 +1. 那麼如果A沒有釋放,B就一直不會釋放,因為A對B有擁有權。 同理,B沒有釋放,A也一直釋放不掉,因為B對A也有擁有權。 因此A 和 B 的dealloc 都會不執行,造成記憶體洩露. 
程式碼演示如下(只寫出了核心程式碼):
A *a =  [[A alloc] init] // a 引用計數:1
B *b =  [[B alloc] init] // b 引用計數:1
a.b = b; // b 引用計數: 2
b.delegate = a; // a 引用計數: 2
[a release]; // a引用計數: 1
[b release]; // b引用計數: 1
// 最終 A 和 B 都釋放不掉。
assign則是直接賦值,並不會引起引用計數增加,因此使用assign 不會出現記憶體洩露。
程式碼演示如下(只寫出了核心程式碼):
A *a =  [[A alloc] init] // a 引用計數:1
B *b =  [[B alloc] init] // b 引用計數:1
a.b = b; // b 引用計數: 2
b.delegate = a; // a 引用計數: 1
[a release]; // a引用計數: 0, b引用計數:1(在a的dealloc裡面_b被釋放了)
[b release]; // b引用計數: 0
// 最終 A 和 B 都可以釋放掉。
 
13.NSNotification和KVO的區別和用法是什麼?什麼時候應該使用通知,什麼時候應該使用KVO,它們的實現上有什麼區別?
答:通知和KVO都是觀察者模式的體現,二者側重點有些不同。
通知往往用於1對多的場景,多個觀察者觀察一個通知,一旦這個通知被通知中心post,所有觀察者都可以做出響應。具體的實現流程是:(1)通知中心通過addObserver方法新增觀察者,其實是把觀察者和通知進行繫結,多次使用addObserver方法可以為同一個通知新增多個觀察者。(2)通知中心傳送通知。(3)各個觀察者做各自的處理。(4)在觀察者銷燬之前(dealloc中),從通知中心移除觀察者。
KVO多用於1對1的場景,一個物件去觀察另外一個物件的屬性值有沒有發生變化,一旦發生變化,觀察者做出響應。具體的流程是:(1)被觀察者新增觀察者,指定觀察者觀察的屬性。(2)被觀察者的屬性在某一時間發生了變化。(3)觀察者做出響應。(4)在觀察者銷燬之前,先移除觀察者。
KVO其實也可以1對多,就是多個觀察者觀察同一個物件同一個屬性的變化。KVO和通知給人的感覺一個主動通知(通知會由通知中心主動post),一個是被動通知(KVO,觀察者一直盯著屬性變沒變,一旦變化,自己就做出響應。被觀察的物件不是主動告知你我變了)。
 
23.定義一個返回值為字串型別,引數是int型別的Block。並且呼叫該Block。
答:Block定義如下所示:
NSString * (^block)(int a) = ^ NSString * (int a){
       return [NSString  stringWithFormat:“%d”,a];
};
Block呼叫:
       NSString *str = block(10);
24. 請談談你對block和delegate模式認識?
答:無論是block還是delegate模式本質上都是回撥,使用block,其優點是回撥的block程式碼塊直接就放在了block賦值的地方,使程式碼更為緊湊,缺點是block內使用到當前類的例項變數的時候,需要注意迴圈引用的問題,即需要使用__block(MRC下)或者__weak(ARC下)定義一個弱引用的self出來,block裡面使用弱引用的self去操作屬性或呼叫方法。delegate模式不用像block一樣做特殊處理,但是如果多個物件設定的代理是同一個物件,就需要在delegate方法中判斷當前執行代理的是哪個物件。
 
1、block的作用?
       1.    __block物件在block中是可以被修改、重新賦值的;
       2.    __block物件在block中不會被block強引用一次,從而不會出現迴圈引用的問題。
 
2、block裡面能不能修改靜態變數(能,__block可以)為什麼要用__block
 
你可以指定引入一個變數為可更改的,即讀-寫的,通過應用__block 儲存型別修 飾符。區域性變數的__block 的儲存和 register、auto、static 等儲存型別相似,但它們之 間不相容。
__block 變數儲存在變數共享的作用域範圍內,所有的 blocks 和 block 副本都宣告 或建立在和變數的作用域相同範圍內。所以,如果任何 blocks 副本宣告在棧內並未超 出棧的結束時,該儲存會讓棧幀免於被破壞(比如封裝為以後執行)。同一作用域範 圍內給定的多個 block 可以同時使用一個共享變數
作為一種優化,block儲存在棧上面,就像blocks本身一樣。如果使用Block_copy 拷貝了 block 的一個副本(或者在 Objective-C 裡面給 block 傳送了一條 copy 訊息), 變數會被拷貝到堆上面。所以一個__block 變數的地址可以隨時間推移而被更改。
使用__block 的變數有兩個限制:它們不能是可變長的陣列,並且它們不能是包 含有 C99 可變長度的陣列變數的資料結構。
 
 
3、宣告一個block
 
宣告block
 
int (^myblock) (int)
 
說明:第一個 int 是 block 的返回值    myblock 是 block 變數     第二個 int 是引數
 
// 舉例
在.h中
typedef void(^MyBlock)(int value);
@property (nonatomic,weak) MyBlock block;
-(void)setMyBlock:(void(^)(int value)) block;
 
在.m中
-(void)setMyBlock:(void(^)(int value)) block {
if (block) {
self.block=block;
}
}
 
11、ios使用block應當注意什麼?
(1)block 在實現時就會對它引用到的它所在方法中定義的棧變數進行一次只讀拷貝,然後在 block 塊內使用該只讀拷貝。
(2)非內聯(inline) block 不能直接訪問 self,只能通過將 self 當作引數傳遞到 block 中才能使用,並且此時的 self 只能通過 setter 或 getter 方法訪問其屬性,不能使用句點式方法。但內聯 block 不受此限制。
(3)使用 weak–strong dance 技術來避免迴圈引用
(4)block 記憶體管理分析
block 其實也是一個 NSObject 物件,並且在大多數情況下,block 是分配在棧上面的,只有當 block 被定義為全域性變數或 block 塊中沒有引用任何 automatic 變數時,block 才分配在全域性資料段上。 __block 變數也是分配在棧上面的。在 ARC 下,編譯器會自動檢測為我們處理了 block 的大部分記憶體管理,但當將 block 當作方法引數時候,編譯器不會自動檢測,需要我們手動拷貝該 block 物件。
在 ARC 下,對 block 變數進行 copy 始終是安全的,無論它是在棧上,還是全域性資料段,還是已經拷貝到堆上。對棧上的 block 進行 copy 是將它拷貝到堆上;對全域性資料段中的 block 進行 copy 不會有任何作用;對堆上的 block 進行 copy 只是增加它的引用記數。
如果棧上的 block 中引用了__block 型別的變數,在將該 block 拷貝到堆上時也會將 __block 變數拷貝到堆上如果該 __block 變數在堆上還沒有對應的拷貝的話,否則就增加堆上對應的拷貝的引用記數。
 
2.kvo除了能觀察屬性外,能不能觀察物件
不能觀察物件
KVO,即:Key-Value Observing,它提供一種機制,當指定的物件的屬性被修改後,則物件就會接受到通知。簡單的說就是每次指定的被觀察的物件的屬性被修改後,KVO就會自動通知相應的觀察者了
KVO是一個物件能夠觀察另外一個物件的屬性的值,並且能夠發現值的變化。這是一個物件與另外一個物件保持同步的一種方法,即當另外一種物件的狀態發生改變時,觀察物件馬上作出反應。它只能用來對屬性作出反應,而不會用來對方法或者動作作出反應。
 
實現原理:當為某一個物件屬性註冊監聽的時候,該物件的isa指標就會指向一箇中間類,而不是本來物件真實的類。所以說,物件的isa指標可以改變,我們的程式最好不要依賴isa指標。
簡而言之就是:
1、當一個object有觀察者時,動態建立這個object的類的子類
2、對於每個被觀察的property,重寫其set方法
3、在重寫的set方法中呼叫- willChangeValueForKey:和- didChangeValueForKey:通知觀察者
4、當一個property沒有觀察者時,刪除重寫的方法
5、當沒有observer觀察任何一個property時,刪除動態建立的子類
 
10、簡述在app中所應用到設計模式
(一)代理模式
應用場景:當一個類的某些功能需要由別的類來實現,但是又不確定具體會是哪個類實現。
優勢:解耦合
敏捷原則:開放-封閉原則
例項:tableview的 資料來源delegate,通過和protocol的配合,完成委託訴求。
列表row個數delegate
自定義的delegate
 
 
(二)觀察者模式
應用場景:一般為model層對,controller和view進行的通知方式,不關心誰去接收,只負責釋出資訊。
優勢:解耦合
敏捷原則:介面隔離原則,開放-封閉原則
例項:Notification通知中心,註冊通知中心,任何位置可以傳送訊息,註冊觀察者的物件可以接收。
kvo,鍵值對改變通知的觀察者,平時基本沒用過。
(三)MVC模式
應用場景:是一中非常古老的設計模式,通過資料模型,控制器邏輯,檢視展示將應用程式進行邏輯劃分。
優勢:使系統,層次清晰,職責分明,易於維護
敏捷原則:對擴充套件開放-對修改封閉
例項:model-即資料模型,view-檢視展示,controller進行UI展現和資料互動的邏輯控制。
 
 
(四)單例模式
應用場景:確保程式執行期某個類,只有一份例項,用於進行資源共享控制。
優勢:使用簡單,延時求值,易於跨模組
敏捷原則:單一職責原則
例項:[UIApplication sharedApplication]。
注意事項:確保使用者只能通過 getInstance方法才能獲得,單例類的唯一例項。
java,C++中使其沒有公有建構函式,私有化並覆蓋其建構函式。
object c中,重寫allocWithZone方法,保證即使使用者用alloc方法直接建立單例類的例項,
返回的也只是此單例類的唯一靜態變數。
 
 
(五)策略模式
應用場景:定義演算法族,封裝起來,使他們之間可以相互替換。
優勢:使演算法的變化獨立於使用演算法的使用者
敏捷原則:介面隔離原則;多用組合,少用繼承;針對介面程式設計,而非實現。
例項:排序演算法,NSArray的sortedArrayUsingSelector;經典的鴨子會叫,會飛案例。
注意事項:1,剝離類中易於變化的行為,通過組合的方式嵌入抽象基類
2,變化的行為抽象基類為,所有可變變化的父類
3,使用者類的最終例項,通過注入行為例項的方式,設定易變行為
防止了繼承行為方式,導致無關行為汙染子類。完成了策略封裝和可替換性。
 
 
(六)工廠模式
應用場景:工廠方式建立類的例項,多與proxy模式配合,建立可替換代理類。
優勢:易於替換,面向抽象程式設計,application只與抽象工廠和易變類的共性抽象類發生呼叫關係。
敏捷原則:DIP依賴倒置原則
例項:專案部署環境中依賴多個不同型別的資料庫時,需要使用工廠配合proxy完成易用性替換
注意事項:專案初期,軟體結構和需求都沒有穩定下來時,不建議使用此模式,因為其劣勢也很明顯,
增 加了程式碼的複雜度,增加了呼叫層次,增加了記憶體負擔。所以要注意防止模式的濫用。
 
8.使用block和使用delegate完成委託模式有什麼優點?
委託模式在iOS中大量應用,其在設計模式中是介面卡模式中的物件介面卡,Objective-C中使用id型別指向一切物件,使委託模式更為簡潔。
 
block
優點:
1.語法簡潔,實現回撥不需要顯示的呼叫方法,程式碼更為緊湊。
2.增強程式碼的可讀性和可維護性。
3.配合GCD優秀的解決多執行緒問題。
缺點:
1.Block中得程式碼將自動進行一次retain操作,容易造成記憶體洩露。
2.Block內預設引用為強引用,容易造成迴圈引用。
 
代理:
優點:
1.減少程式碼的耦合性,使事件監聽和事件處理相分離。
2.清晰的語法定義,減少維護成本,較強的程式碼可讀性。
3.不需要建立第三方來監聽事件和傳輸資料。
4.一個控制器可以實現多個代理,滿足自定義開發需求,可選必選有較大的靈活性。
缺點:
1.實現委託的程式碼過程比較繁瑣。
2.當實現跨層傳值監聽的時候將加大程式碼的耦合性,並且程式的層次結構將變的混亂。
3.當對多個物件同時傳值響應的時候,委託的易用性將
 
10.何時使用代理,何時使用通知;
代理:一般控制元件用的比較多,其實也可以用block實現,如果實現的介面比較多的話,建議用代理,如UITableview。
如果一個類能夠獲取到通知的物件,這種情況下,我們用代理的效率會更高,而且能夠更好的實現對要代理的物件的管理。
 
通知:這東西是全域性的,而且是同步的,如果你要全域性傳送訊息,並且做的事情時間不長,不會阻塞執行緒的話,建議使用。
如果一個通知的傳送者有多個接受者,而且接受的位置完全不確定,那麼這種情況下用通知是比較好的方式
 
37. block在ARC中和MRC中的用法有什麼區別,需要注意什麼
①.對於沒有引用外部變數的Block,無論在ARC還是非ARC下,型別都是__NSGlobalBlock__,這種型別的block可以理解成一種全域性的block,不需要考慮作用域問題。同時,對他進行Copy或者Retain操作也是無效的
②.應注意避免迴圈引用
 
36.  類工廠方法是什麼
 類工廠方法的實現是為了向客戶提供方便,它們將分配和初始化合在一個步驟中, 返回被建立的物件,並
進行自動釋放處理。這些方法的形式是+ (type)className...(其中 className不包括任何字首)。
工廠方法可能不僅僅為了方便使用。它們不但可以將分配和初始化合在一起,還可以 為初始化過程提供對
象的分配資訊。
類工廠方法的另一個目的是使類(比如NSWorkspace)提供單件例項。雖 然init...方法可以確認一
個類在每次程式執行過程只存在一個例項,但它需要首先分配一個“生的”例項,然後還必須釋放該例項。
工廠 方法則可以避免為可能沒有用的物件盲目分配記憶體。
 
43.代理和協議什麼區別
代理是一種概念,協議是一種技術,代理是用協議來實現的,代理 是 2 個物件之間通訊的一種方式。 代理主要做反向傳值的。實現系統的一些回撥方法,比如 scrollview 滑動事件,選擇照片,asi 網路下載完成等.iOS開發和Objective-c區別
 
50.在block內如何修改block外部變數?
預設情況下,在block中訪問的外部變數是複製過去的,即:寫操作不對原變數生效。但是你可以加上__block來讓其寫操作生效,示例程式碼如下:
__block int a = 0;
void  (^foo)(void) = ^{
    a = 1;
}
f00();
//這裡,a的值被修改為1
 
53.  使用block時什麼情況會發生引用迴圈,如何解決?
一個物件中強引用了block,在block中又使用了該物件,就會發射迴圈引用。 解決方法是將該物件使用__weak或者__block修飾符修飾之後再在block中使用。
id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self該方法可以設定巨集
id __block weakSelf = self;
 
block中的weak self,是任何時候都需要加的麼?
(2)block
block在copy時都會對block內部用到的物件進行強引用(ARC)或者retainCount增1(非ARC)。在ARC與非ARC環境下對block使用不當都會引起迴圈引用問題,一般表現為,某個類將block作為自己的屬性變數,然後該類在block的方法體裡面又使用了該類本身,簡單說就是self.someBlock = ^(Type var){[self dosomething];或者self.otherVar = XXX;或者_otherVar = ...};block的這種迴圈引用會被編譯器捕捉到並及時提醒
 
95.哪些類不適合使用單例模式?即使他們在週期中只會出現一次。
工具類,不需要儲存資料的.
 
簡明概要的說明了KVO和NSNotification的區別:
和delegate一樣,KVO和NSNotification的作用也是類與類之間的通訊,與delegate不同的是1)這兩個都是負責發出通知,剩下的事情就不管了,所以沒有返回值;2)delegate只是一對一,而這兩個可以一對多。這兩者也有各自的特點。
1)KVO的使用:
被觀察者發出  addObserver:forKeyPath:options:context:  方法來新增觀察者。
然後只要被觀察者的keyPath值變化(注意:單純改變其值不會呼叫此方法,只有通過getters和setters來改變值才會觸發KVO),就會在觀察者裡呼叫方法observeValueForKeyPath:ofObject:change:context:
因此觀察者需要實現方法 observeValueForKeyPath:ofObject:change:context: 來對KVO發出的通知做出響應。
這 些程式碼都只需在觀察者裡進行實現,被觀察者不用新增任何程式碼,所以誰要監聽誰註冊,然後對響應進行處理即可,使得觀察者與被觀察者完全解耦,運用很靈活很 簡便;但是KVO只能檢測類中的屬性,並且屬性名都是通過NSString來查詢,編譯器不會幫你檢錯和補全,純手敲所以比較容易出錯。
 
2)NSNotification的使用
這裡的通知不是由被觀察者發出,而是由NSNotificationCenter來統一發出,而不同通知通過唯一的通知標識名notificationName來區分,標識名由傳送通知的類來起。
首先被觀察者自己在必要的方法A裡,通過方法postNotificationName:object:來發出通知notificationName這樣傳送通知者這邊的工作就完成了,每次A被呼叫,就會傳送一次通知notificationName。
然後誰要監聽A的變化,就通過[NSNotificationCenter defaultCenter]的方法addObserver:selector:name:object:為觀察者註冊監聽name為notificationName的通知然後每次發出name為notificationName的通知時,註冊監聽後的觀察者就會呼叫其自己定義的方法notificationSelector來進行響應。
NSNotification的特點呢,就是需要被觀察者先主動發出通知,然後觀察者註冊監聽後再來進行響應,比KVO多了傳送通知的一步,但是其優點是監聽不侷限於屬性的變化,還可以對多種多樣的狀態變化進行監聽,監聽範圍廣,使用也更靈活。
 
MVC模式及好處?
 
 MVC是三個單詞的縮寫,分別為:
    模型(Model),檢視(View)和控制Controller)。
MVC模式的目的就是實現Web系統的職能分工。
Model層實現系統中的業務邏輯,通常可以用JavaBean或EJB來實現。 
View層用於與使用者的互動,通常用JSP來實現。
Controller層是Model與View之間溝通的橋樑,它可以分派使用者的請求並選擇恰當的檢視以用於顯示,同時它也可以解釋使用者的輸入並將它們對映為模型層可執行的操作。
MVC模式的好處
1.各施其職,互不干涉
在MVC模式中,三個層各施其職,所以如果一旦哪一層的需求發生了變化,就只需要更改相應的層中的程式碼而不會影響到其它層中的程式碼。 
2.有利於開發中的分工
在MVC模式中,由於按層把系統開,那麼就能更好的實現開發中的分工。網頁設計人員可以進行開發檢視層中的JSP,對業務熟悉的開發人員可開發業務層,而其它開發人員可開發控層。 
3.有利於元件的重用
分層後更有利於元件的重用。如控制層可獨立成一個能用的元件,檢視層也可做成通用的操作介面。
   MVC(Model-View-Controller)應用程式結構被用來分析分散式應用程式的特徵。這種抽象結構能有助於將應用程式分割成若干邏輯部件,使程式設計變得更加容易。
MVC結構提供了一種按功能對各種物件進行分割的方法(這些物件是用來維護和表現數的),其目的是為了將各物件間的耦合程度減至最小。MVC結構本來是為了將傳統的輸入(input)、處理(processing)、輸出(output)任務運用到圖形化使用者互動模型中而設計的。但是,將這些概念運用於基於Web的企業級多層應用領域也是很適合的。
在MVC結構中,模型(Model)代表應用程式的資料(data)和用於控制訪問和修改這些資料的業務規則(business rule)。通常模型被用來作為對現實世界中一個處理過程的軟體近似,當定義一個模型時,可以採用一般的簡單的建模技術。
當模型發生改變時,它會通知視(View),並且為視提供查詢模型相關狀態的能力。同時,它也為控制器(Controller)提供訪問封裝在模型內部的應用程式功能的能力。
一個視(View)用來組織模型的內容。它從模型那裡獲得資料並指定這些資料如何表現。當模型變化時,視負責維持資料表現的一致性。視同時將使用者要求告知控制器(Controller)。
控制器(Controller)定義了應用程式的行為;它負責對來自視的使用者要求進行解釋,並把這些要求對映成相應的行為,這些行為由模型負責實現。在獨立執行的GUI客戶端,使用者要求可能是一些滑鼠單擊或是選單選擇操作。在一個Web應用程式中,它們的表現形式可能是一些來自客戶端的GET或POST的 HTTP請求。模型所實現的行為包括處理業務和修改模型的狀態。根據使用者要求和模型行為的結果,控制器選擇一個視作為對使用者請求的應答。通常一組相關功能集對應一個控制器。
1) 各施其職,互不干涉
在MVC模式中,三個層各施其職,所以如果一旦哪一層的需求發生了變化,就只需要更改相應的層中的程式碼而不會影響到其它層中的程式碼。假如業務發生了變化,如在取文章時可能webmaster把一些文章作了無效標誌,不能直接把所有文章取出來,只能取出有效的文章,這時業務就發生了改變。再設想一下,如果這個業務邏輯在100個頁面中都要用到,那麼MVC模式就體現了它的靈活性。我們可以不更改任何JSP,只要更改model層中的相應類中的SQL語句即可。
2) 有利於開發中的分工
在MVC模式中,由於按層把系統開,那麼就能更好的實現開發中的分工。網頁設計人員可以進行開發檢視層中的JSP,對業務熟悉的開發人員可開發業務層,而其它開發人員可開發控制層。
3) 有利於元件的重用
分層後更有利於元件的重用。如控制層可獨立成一個能用的元件,視力層也可做成通用的操作介面
 
10、宣告block屬性的時候為什麼⽤用copy?
避免block被系統釋放,因為⼀一開始block是在棧中的,只有copy後的block才會
在堆中。
Block屬性的宣告,⾸首先需要⽤用copy修飾符,因為只有copy後的Block才會在堆 中,棧中的Block的⽣生命週期是和棧繫結的,避免編譯器將其釋放;
(擴充)block與執行緒安全 另⼀一個需要注意的問題是關於執行緒安全,在宣告Block屬性時需要確認“在調⽤用
Block時另⼀一個執行緒有沒有可能去修改Block?”這個問題,如果確定不會有這種 情況發⽣生的話,那麼Block屬性宣告可以⽤用nonatomic。如果不肯定的話(通常 情況是這樣的),那麼你⾸首先需要宣告Block屬性為atomic,也就是先保證變數 的原⼦子性(Objective-C並沒有強制規定指標讀寫的原⼦子性,C#有)。
⽐比如這樣⼀一個Block型別: typedef void (^MyBlockType)(int);
屬性宣告:
@property (copy) MyBlockType myBlock;
這⾥裡ARC和⾮非ARC宣告都是⼀一樣的,當然注意在⾮非ARC下要release Block。
但是,有了atomic來保證基本的原⼦子性還是沒有達到執行緒安全的,接著在調⽤用 時需要把Block先賦值給本地變數,以防⽌止Block突然改變。因為如果不這樣的 話,即便是先判斷了Block屬性不為空,在調⽤用之前,⼀一旦另⼀一個執行緒把Block 屬性設空了,程式就會crash,如下程式碼:
if (self.myBlock)
{
//此時,⾛走到這⾥裡,self.myBlock可能被另⼀一個執行緒改為空,造成crash //注意:atomic只會確保myBlock的原⼦子性,這種操作本⾝身還是⾮非執行緒安全的 self.myBlock(123);
}
所以正確的程式碼是(ARC): MyBlockType block = self.myBlock; //block現在是本地不可變的
if (block)
{ block(123); }
在⾮非ARC下則需要⼿手動retain⼀一下,否則如果屬性被置空,本地變數就成了野指 針了,如下程式碼:
//⾮非ARC
MyBlockType block = [self.myBlock retain];
if (block)
{ block(123); }
[block release];
 
4.(口述)NSNotification和KVO的區別和用法是什麼?什麼時候應該使用通知,什麼時候應該使用KVO,它們的實現上有什麼區別嗎?如果用protocol和delegate(或者delegate的Array)來實現類似的功能可能嗎?如果可能,會有什麼潛在的問題?如果不能,為什麼?
 
2、非自動記憶體管理情況下怎麼做單例模式
非ARC記憶體管理模式下物件必須手動釋放,為了防止那個唯一的單例物件被釋放掉,則只需要重寫下面的幾個方法即可
       +     (instancetype) allocWithZone:(struct _NSZone *)zone
       -      (instancetype) copyWithZone:(NSZone*)zone
       -      (id) retain
       -      (oneway void) release
       -      (instancetype) autorelease
       -      (unsigned) retainCount

4、What is Singleton pattern? Please try to implement one
單例模式的意思就是隻有一個例項。單例模式確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。這個類稱為單例類。
在iOS中,單例有兩種實現方式。根據執行緒安全的實現來區分,一種是使用@synchronized,另一種是使用GCD的dispatch_once函式。
要實現單例,首先需要一個static的指向類本身的物件,其次需要一個初始化類函式。下面是兩種實現的程式碼。
1、@synchronized
static InstanceClass *instance;
+ (InstanceClass *)defaultInstance{
    @synchronized (self){
        if (instance == nil) {
            instance = [[InstanceClass alloc] init];
        }
    }
    
    return instance;
}
 
2、GCD
static InstanceClass *instance;
+ (InstanceClass *)defaultInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[InstanceClass alloc] init];
    });
    
    return instance;
}
 
 
2.MRC下的單例需要注意什麼
 
因為 單例物件 是用 static 標記過的 , 因此存放在 靜態區 . 所以在 MRC 中 不需要 由程式設計師 去管理 , 因此要去覆蓋一些 記憶體 管理的方法 .
實現部分與 ARC 一致 , 只需要 覆蓋 一些 MRC 中 記憶體 管理 的方法:
 
* -  (id)retain .   單例中不需要增加引用計數器. return self.
 
* - (id)autorelease .   只有堆中的物件才需要 . 單例中不需要.return self.
 
* - (NSUInteger)retainCount . ( 可寫可不寫 , 防止引起誤解 ). 單例中不需要修改引用計數,返回最大的無符號整數即可 .return UINT_MAX;
 
       *     - (oneway void)release . 不需要 release. 直接覆蓋 , 宣告也不做 .
 
單例模式(ARC)與(MRC)

相關文章