成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

有一種Block叫Callback,有一種Callback叫CompletionHandler

移動(dòng)開發(fā) iOS
iOS10推送部分的API,大量使用了 CompletionHandler 這種命名方式,那么本文我們將對(duì)比下這種 Block 的特殊性,以便更好的理解和在自己的項(xiàng)目中實(shí)踐 CompletionHandler 樣式的 Blcok。

【引言】iOS10推送部分的API,大量使用了 CompletionHandler 這種命名方式,那么本文我們將對(duì)比下這種 Block 的特殊性,以便更好的理解和在自己的項(xiàng)目中實(shí)踐 CompletionHandler 樣式的 Blcok。

正文

我們作為開發(fā)者去集成一個(gè) Lib (也可以叫輪子、SDK、下文統(tǒng)一叫 Lib)時(shí),我們會(huì)發(fā)現(xiàn)我們遇到的 Block, 按照功能的角度劃分,其實(shí)可以分為這幾種:

  • Lib 通知開發(fā)者,Lib操作已經(jīng)完成。一般命名為 Callback
  • 開發(fā)者通知 Lib,開發(fā)者的操作已經(jīng)完成。一般可以命名為 CompletionHandler。

這兩處的區(qū)別: 前者是 “Block 的執(zhí)行”,后者是 “Block 的填充”。

Callback vs CompletionHandler 命名與功能的差別,Apple 也沒有明確的編碼規(guī)范指出過,只不過如果按照“執(zhí)行與填充”的功能劃分的話,callback 與 completionHandler 的命名可以區(qū)分開來對(duì)待。同時(shí)也方便調(diào)用者理解 block 的功能。但總體來說,Apple 官方的命名中,“Block 填充“這個(gè)功能一般都會(huì)命名為 “completionHandler”,“Block 執(zhí)行”這個(gè)功能大多命名為了“callback” ,也有少部分命名為了 “completionHandler”。

比如:

NSURLSession 中,下面的函數(shù)將 “callback” 命名為了 “completionHandler”:

  1. - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; 

我們常常見到 CompletionHandler 被用到了***種場(chǎng)景,而***種場(chǎng)景“Block 執(zhí)行”命名為 Callback 則更合適。

不是所有 Block 都適合叫做 CompletionHandler

一般情況下,CompletionHandler 的設(shè)計(jì)往往考慮到多線程操作,于是,你就完全可以異步操作,然后在線程結(jié)束時(shí)執(zhí)行該 CompletionHandler,下文的例子中會(huì)講述下 CompletionHandler 方式在多線程場(chǎng)景下的一些優(yōu)勢(shì)。

CompletionHandler + Delegate 組合

在 iOS10 中新增加的 UserNotificaitons 中大量使用了這種 Block,比如:

  1. - (void)userNotificationCenter:(UNUserNotificationCenter *)center 
  2. didReceiveNotificationResponse:(UNNotificationResponse *)response 
  3.          withCompletionHandler:(void (^)(void))completionHandler; 

 

文檔 對(duì) completionHandler 的注釋是這樣的:

  1. The block to execute when you have finished processing the user’s response. You must execute this block from your method and should call it as quickly as possible. The block has no return value or parameters. 

同樣在這里也有應(yīng)用:

  1. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task 
  2. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
  3. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler; 

 

還有另外一個(gè)也非常普遍的例子(Delegate 方式使用URLSession 時(shí)候必不可少的 4個(gè)代理函數(shù)之一 )

  1. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask 
  2.                                  didReceiveResponse:(NSURLResponse *)response 
  3.                                   completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler; 

 

在代理方法實(shí)現(xiàn)代碼里面,若是不執(zhí)行 completionHandler(NSURLSessionResponseAllow) 話,http請(qǐng)求就終止了。

CompletionHandler + Block 組合

函數(shù)中將函數(shù)作為參數(shù)或者返回值,就叫做高階函數(shù)。

按照這種定義,Block 中將 Block 作為參數(shù),這也就是高階函數(shù)。

結(jié)合實(shí)際的應(yīng)用場(chǎng)景來看一個(gè)例子:

如果有這樣一個(gè)需求:

拿我之前的一個(gè) IM 項(xiàng)目 ChatKit-OC (開源的,下面簡(jiǎn)稱 ChatKit)為例,當(dāng)你的應(yīng)用想要集成一個(gè) IM 服務(wù)時(shí),可能這時(shí)候,你的 APP 已經(jīng)上架了,已經(jīng)有自己的注冊(cè)、登錄等流程了。用 ChatKit 進(jìn)行聊天很簡(jiǎn)單,只需要給 ChatKit 一個(gè) id 就夠了。聊天是正常了,但是雙方只能看到一個(gè)id,這樣體驗(yàn)很不好。但是如何展示頭像、昵稱呢?于是就設(shè)計(jì)了這樣一個(gè)接口,-setFetchProfilesBlock: 。

這是上層(APP)提供用戶信息的 Block,由于 ChatKit 并不關(guān)心業(yè)務(wù)邏輯信息,比如用戶昵稱,用戶頭像等。用戶可以通過 ChatKit 單例向 ChatKit 注入一個(gè)用戶信息內(nèi)容提供 Block,通過這個(gè)用戶信息提供 Block,ChatKit 才能夠正確的進(jìn)行業(yè)務(wù)邏輯數(shù)據(jù)的繪制。

示意圖如下:

 

 

 

 

具體實(shí)現(xiàn)如下:

方法定義如下:

  1. /*! 
  2. *  @brief The block to execute with the users' information for the userIds. Always execute this block at some point when fetching profiles completes on main thread. Specify users' information how you want ChatKit to show. 
  3. *  @attention If you fetch users fails, you should reture nil, meanwhile, give the error reason. 
  4. */ 
  5. typedef void(^LCCKFetchProfilesCompletionHandler)(NSArray> *users, NSError *error); 
  6.   
  7. /*! 
  8. *  @brief When LeanCloudChatKit wants to fetch profiles, this block will be invoked. 
  9. *  @param userIds User ids 
  10. *  @param completionHandler The block to execute with the users' information for the userIds. Always execute this block at some point during your implementation of this method on main thread. Specify users' information how you want ChatKit to show. 
  11. */ 
  12. typedef void(^LCCKFetchProfilesBlock)(NSArray *userIds, LCCKFetchProfilesCompletionHandler completionHandler); 
  13.   
  14. @property (nonatomic, copy) LCCKFetchProfilesBlock fetchProfilesBlock; 
  15.   
  16. /*! 
  17. *  @brief Add the ablitity to fetch profiles. 
  18. *  @attention  You must get peer information by peer id with a synchronous implementation. 
  19. *              If implemeted, this block will be invoked automatically by LeanCloudChatKit for fetching peer profile. 
  20. */ 
  21. - (void)setFetchProfilesBlock:(LCCKFetchProfilesBlock)fetchProfilesBlock; 

 

用法如下所示:

  1. #warning 注意:setFetchProfilesBlock 方法必須實(shí)現(xiàn),如果不實(shí)現(xiàn),ChatKit將無法顯示用戶頭像、用戶昵稱。以下方法循環(huán)模擬了通過 userIds 同步查詢 users 信息的過程,這里需要替換為 App 的 API 同步查詢 
  2.     [[LCChatKit sharedInstance] setFetchProfilesBlock:^(NSArray *userIds, 
  3.                              LCCKFetchProfilesCompletionHandler completionHandler) { 
  4.          if (userIds.count == 0) { 
  5.              NSInteger code = 0; 
  6.              NSString *errorReasonText = @"User ids is nil"
  7.              NSDictionary *errorInfo = @{ 
  8.                                          @"code":@(code), 
  9.                                          NSLocalizedDescriptionKey : errorReasonText, 
  10.                                          }; 
  11.              NSError *error = [NSError errorWithDomain:NSStringFromClass([self class]) 
  12.                                                   code:code 
  13.                                               userInfo:errorInfo]; 
  14.   
  15.              !completionHandler ?: completionHandler(nil, error); 
  16.              return
  17.          } 
  18.   
  19.          NSMutableArray *users = [NSMutableArray arrayWithCapacity:userIds.count]; 
  20. #warning 注意:以下方法循環(huán)模擬了通過 userIds 同步查詢 users 信息的過程,這里需要替換為 App 的 API 同步查詢 
  21.   
  22.          [userIds enumerateObjectsUsingBlock:^(NSString *_Nonnull clientId, NSUInteger idx, 
  23.                                                BOOL *_Nonnull stop) { 
  24.              NSPredicate *predicate = [NSPredicate predicateWithFormat:@"peerId like %@", clientId]; 
  25.              //這里的LCCKContactProfiles,LCCKProfileKeyPeerId都為事先的宏定義, 
  26.              NSArray *searchedUsers = [LCCKContactProfiles filteredArrayUsingPredicate:predicate]; 
  27.              if (searchedUsers.count > 0) { 
  28.                  NSDictionary *user = searchedUsers[0]; 
  29.                  NSURL *avatarURL = [NSURL URLWithString:user[LCCKProfileKeyAvatarURL]]; 
  30.                  LCCKUser *user_ = [LCCKUser userWithUserId:user[LCCKProfileKeyPeerId] 
  31.                                                        name:user[LCCKProfileKeyName] 
  32.                                                   avatarURL:avatarURL 
  33.                                                    clientId:clientId]; 
  34.                  [users addObject:user_]; 
  35.              } else { 
  36.                  //注意:如果網(wǎng)絡(luò)請(qǐng)求失敗,請(qǐng)至少提供 ClientId! 
  37.                  LCCKUser *user_ = [LCCKUser userWithClientId:clientId]; 
  38.                  [users addObject:user_]; 
  39.              } 
  40.          }]; 
  41.          // 模擬網(wǎng)絡(luò)延時(shí),3秒 
  42.          //         sleep(3); 
  43.   
  44. #warning 重要:completionHandler 這個(gè) Bock 必須執(zhí)行,需要在你**獲取到用戶信息結(jié)束**后,將信息傳給該Block! 
  45.          !completionHandler ?: completionHandler([users copy], nil); 
  46.      }]; 

 

對(duì)于以上 Fetch 方法的這種應(yīng)用場(chǎng)景,其實(shí)用方法的返回值也可以實(shí)現(xiàn),但是與 CompletionHandler 相比,無法自由切換線程是個(gè)弊端。 

責(zé)任編輯:龐桂玉 來源: iOS大全
相關(guān)推薦

2016-09-27 09:44:33

云計(jì)算柔性云運(yùn)維

2017-11-12 21:32:52

戴爾

2014-02-25 10:11:00

2016-01-08 09:49:19

DockerDocker案例云應(yīng)用開發(fā)

2015-09-22 13:40:50

互聯(lián)網(wǎng)業(yè)務(wù)運(yùn)維

2016-10-14 06:45:23

網(wǎng)絡(luò)安全安全運(yùn)維

2013-03-26 22:32:48

2020-12-09 10:15:34

Pythonweb代碼

2020-12-23 10:10:23

Pythonweb代碼

2022-07-07 10:33:27

Python姿勢(shì)代碼

2022-06-22 09:44:41

Python文件代碼

2021-09-09 08:55:49

節(jié)點(diǎn)累加樹二叉

2012-01-17 11:02:39

2015-01-21 15:35:58

開源

2023-06-02 15:26:37

光纖綜合布線

2015-08-03 09:36:01

賽迪翻譯

2015-08-31 09:27:21

語言界面UI

2017-06-22 16:46:45

2019-08-29 16:05:06

物聯(lián)網(wǎng)

2019-01-21 08:30:01

年終獎(jiǎng)員工人性化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 91精品一区二区三区久久久久 | 欧美日韩高清免费 | 日韩黄a | 在线视频成人 | 女女百合av大片一区二区三区九县 | 亚洲国产情侣 | 国产欧美久久一区二区三区 | 狠狠干影院 | 久久久人成影片免费观看 | 国产视频观看 | 国产综合精品一区二区三区 | 欧美色视频免费 | 久草在线在线精品观看 | 九九色综合 | 性欧美精品一区二区三区在线播放 | 国产欧美日韩精品一区 | 超碰电影| 欧美福利在线 | 久久久精品一区二区三区 | 自拍中文字幕 | 91综合网| 超碰97人人人人人蜜桃 | 欧美日韩一区在线 | 青青久在线视频 | 第一区在线观看免费国语入口 | 日韩国产中文字幕 | av在线播放网 | 亚洲二区在线观看 | 99久久久无码国产精品 | 国产高潮好爽受不了了夜夜做 | 国产一级片在线观看视频 | 一级在线视频 | 国产精品1区| 日韩久久成人 | 日本亚洲一区 | 在线免费观看成人 | 做a网站 | 一级h片 | 日韩电影免费在线观看中文字幕 | 激情小说综合网 | 日韩av一区二区在线观看 |