2016-04-29 74 views
4

快速的問題。取消完成塊

通常情況下,我們做網絡通話,並獲得迴應,我們在完成塊如下

func someAPIcall(input: input, completion: (result: data) -> Void) { 
    ... 
    completion(data) 
} 

返回數據,我使用的功能如下

someAPIcall(input) { 
    (result: data) in 
    print(result) 
    // Update UI, etc 
} 

是它不管怎樣,在任何晚些時候可以取消完成塊?假設我立即撥打網絡電話和popViewController,但如果我取消request,如果數據返回到完成塊,則執行完成任務。

是否有任何機制可以將var分配給閉包,並在稍後取消?

如何在需要時取消該塊的執行,例如viewWillDisappear

+0

你是如何保持竣工塊和取消的活動? – Wain

+0

我問是不是可以這樣做。要取消完成關閉的活動.. – iOS

+0

不是取消完成一次塊它的運行,你無需調用完成塊... – Wain

回答

1

沒有什麼可以讓你直接取消任何塊。因此,塊將在調用時執行。但是,該塊當然可以執行代碼,以確定是否需要執行任何應該執行的操作。

通常你只會有一個弱引用您的塊中的一些對象,如果弱引用是零不執行操作。在其他情況下,您會檢查某個對象的某個屬性。總是有效的簡單方法:使用單個實例屬性「取消」創建一個平凡的類。創建並獲取一個實例,讓該塊引用它,當您要取消該塊時將「已取消」屬性設置爲true,並且回調將檢查該設置。 (同樣,你可以把它作爲一個弱引用,如果調用者不再感興趣,他們可以放棄那個實例)。

2

我的猜測是你在完成塊中強烈地保持自我。如果您在捕獲列表中傳遞給自己的弱引用,那麼如果釋放視圖控制器,則不會執行您的操作。

someAPIcall(input) { [weak self] result in 
    guard let strongSelf = self else { return } 

    strongSelf.label.text = ... 
} 

請注意,只有當您在塊中執行的任務在自我上執行時纔會有效。 someAPIcall仍保持對完成塊的引用,但完成塊對視圖控制器的引用較弱。 (從技術上講,你可以使用weak self的值來檢查是否執行其他任務)。

如果這還不夠,您可以訪問的someAPIcall實施,那麼你可以添加一個cancel()方法(如其他人所說的)比將停止通話,並釋放塊。

5

你一定不能從存在擦除完成塊,但因爲它是你完成塊的,你可以很容易地只是沒有被調用時做什麼:

func someAPIcall(input: input, completion: (result: data) -> Void) { 
    guard somethingOrOther else {return} 
    // ... 
    completion(data) 
} 

somethingOrOther可能是self的屬性,或者(正如你已經被告知的),你可能會檢查是否self甚至還存在。

這與NSOperation使用的機制並無太大差別,NSOperation可以在實際做任何事情之前檢查自己的cancelled屬性。

0

有很多不同的方法來做到這一點。正確的答案取決於你的特定用例,以及你設計API交互的方式。 NSOperations有一個很好的取消/依賴管理/完成工作流程,所以如果你能夠將你的API交互放在NSOperationQueue中,這可能是最好的方式。我用於一些更簡單的交互的另一種可能性是簡單地保留對與視圖控制器的特定視圖交互相對應的NSURLSessionTasks的引用,並根據需要取消它們。例如:

//: Playground - noun: a place where people can play 

import UIKit 

class MyViewController: UIViewController, UISearchBarDelegate { 

    var tasks = [NSURLSessionTask]() 
    let client = MyAPIClient() 

    deinit { 
     cancelAllTasks() 
    } 

    func cancelAllTasks() { 
     tasks.forEach { $0.cancel() } 
    } 

    func cancelAllSearchTasks() { 
     tasks.filter({ $0.taskDescription == MyAPIClient.TaskDecription.search.rawValue }).forEach { $0.cancel() } 
    } 

    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { 
     // Cancel previous search as user types a new search 
     cancelAllSearchTasks() 

     guard let text = searchBar.text else { 
      return 
     } 

     tasks.append(client.search(text) { [weak self] results in 
      // ... 
     }) 
    } 

} 

class MyAPIClient { 

    enum TaskDecription: String { 
     case search 
    } 

    let session = NSURLSession() 

    func search(text: String, completion: (result: [String]) -> Void) -> NSURLSessionTask { 
     let components = NSURLComponents() 
     components.scheme = "http" 
     components.host = "myapi.com" 
     components.queryItems = [NSURLQueryItem(name: "q", value: text)] 
     guard let url = components.URL else { 
      preconditionFailure("invalid search url") 
     } 

     let task = session.dataTaskWithURL(url) { (data, response, error) in 
      // ... 
      completion(result: ["results", "from", "api", "go", "here!"]) 
     } 
     task.resume() 
     task.taskDescription = TaskDecription.search.rawValue 

     return task 
    } 
} 

在這裏,當視圖控制器被釋放時,我們取消所有與此控制器相關的NSURLSessionTasks。我們還取消任何現有的「搜索」api任務,因爲用戶在搜索欄中鍵入內容,這樣我們就不會進行「陳舊」的api調用。

當然,這是一個相當簡單的例子,但你的idea-這是很好的關於網絡的數額的話費您的應用程序進行,並取消他們,如果他們不再需要的是聰明的!