2015年8月31日 星期一

NSOperation及NSOperationQueue與GCD之比較

之前上Stanford iOS 7的課程時有介紹到GCD(Grand Central Dispatch),是一種比較低階的函數,讓code可以在不同的thread中跑。可是假如說我今天要檢查該thread的運作情況,好比說他的優先順序、是否還在運行等,這時候GCD能提供的設定就比較少,於是就需要NSOperation和NSOperationQueue啦~

在Mac OS X 10.6之前,NSOperation跟GCD是採用不同的運作模式,10.6之後NSOperation就改成運作在GCD之上了,換言之他是比較高階的API,但是同時也保有GCD的效能。使用NSOperation時有以下步驟:

  1. 繼承自NSOperation
  2. 覆寫main()
  3. 在main中建立autorelease pool(自動釋放池)
  4. 把code放到autorelease pool中
  5. 針對需求,在外部檢查isCancelled等屬性
至於NSOperation中有以下method:
  1. start:呼叫該函數來執行該operation,但如果沒有特別指定去哪個queue時將會在main queue執行,要特別注意
  2. dependency:可以設定兩個operation的相依性來設定先後順序。舉例來說我今天下載了一段音訊,要等下載完成後才能進行裁剪,GCD中的dispatch_barrier_async()有提供類似的功能
  3. priority:這點是我覺得比較有趣的地方,可針對特定的operation來設定setQueuePriority:,像是NSOperationQueuePriorityVeryLow
  4. completion block:當operation完成後可以在setCompletionBlock:^{}去做其他事情,好比說存檔等等
另外NSOperationQueue相較於NSOperation就更為簡單,僅需要alloc並init即可,之後可調用以下方法:
  1. concurrent operations:這點比較複雜,簡單來說一個queue可以有多個thread,而每個operation會分配到一個thread來執行。舉例來說我有一個queue,然後加入2個operations,這樣建立兩個thread對應到每個operation,所以我這個queue就會有兩個thread
  2. maximum number of concurrent operations:設定每個queue中最多只能有幾個operations來執行
  3. add operation:增加operation到queue,如果要釋放的用使用release方法
  4. pending operation:查詢在queue中有哪些operations。只有「待執行」和「正在執行」的operation才會在queue中。這部分可以用NSArray來保存operations,或是使用NSDictionary來查詢相關的operation
  5. pause(suspend)queue:就是停止queue
  6. cancel operation:如果說該operation尚未執行,呼叫cancel會把operation從queue中移除;如果是正在執行的operation,就要看該operation會不會去檢查isCancelled
  7. addOperationWithBlock:如果當你不想要有NSOperation的子類別卻又想要來queue中執行,就可在該方法中的block插入程式碼。這有點像GCD的block。不過要注意的是若要參考block外的物件,就必須傳入weak屬性的物件
最後綜合比較NSOperation和GCD,我覺得GCD比較簡單、直覺,但是可以操作的範圍不大(因為就是函數),可是其他物件可以繼承NSOperation,獲得了使用多線程的能力。所以我想當要操作物件時就用NSOperation,然後某些片段(下載等需求)就可以用GCD來解決。總之在iOS中多線程是個很重要的觀念,有這麼好用的功能就要好好用它啊~~

Protocol v.s. Delegate

最近剛好寫了一些跟NSOperation的東西,裡面用到許多的Protocol和Delegate,之前學到我們可以宣告一個Protocol,然後讓class去遵循它,可是那為何我們還需要有Delegate? Delegte不也是讓我們去遵循其中的方法來實作嗎?就像是我們在寫UITableView時都要有UITableViewDataSource和UITableViewDelegate來對資料和cell進行設定(因為View無法擁有自己的資料)。那麼兩個這麼像,Protocol和Delegate又有什麼差別呢?

答案是一定有差別的,不然你就不會一直看到這兩個名詞。先複習一下什麼事Protocol,假設當我宣告MyProtocol中有個aMethodInMyProtocol時,任何一個遵循MyProtocol就可調用該方法;另外也可讓實體變數遵循Protocol,譬如我的MyClass中有以下變數:

@property (nonatomic, strong) id  <myprotocol>  instanceThatImplementMyProtocol;

此時該instanceThatImplementMyProtocol就可調用MyProtocol的方法。此外宣告Protocol時也可再遵循其他Protocol,例如:

@protocol Foo
...
@end

只有當你實作了anotherProtocol後,然後你再實作Foo後你才可以說已經實作好該Foo Protocol。那麼在Delegate又是怎麼樣呢?

Delegate說起來是一種設計方法,全名叫做Delegation Design Pattern,Delegate要求遵循該delegation的class去實作Protocol的方法(可以說是一種「方法」),使得該class可以在特定時候使用該Protocol的method。對我來說,Protocol提供一個介面來讓大家共享裡面的方法,然後Delegate會讓用它的class去實現該方法,使用Delegate的好處是可以減弱耦合,達到共享的目的。

另外取自StackoverFlow的解答,我覺得看英文比較能懂:)
The class that uses the delegate knows that its delegate coforms to the protocol, so it knows that it can call the implemented methods at given times.