首页 > 解决方案 > 如何在 Swift 中转义完成块以返回正常的应用程序流程?

问题描述

让我陷入 Swift 的一件事是我的程序中永无止境的链条completionBlocks;我不知道如何让 Swift 说“好的,完成块现在完成了——回到主程序。”

在我的项目中,我正在编写一个简单的棋盘/纸牌游戏,它从一个非常小的 plist 加载其数据。

我写了一个相当简单的 Plist 加载器,它加载 plist 并Data通过完成块返回。它不做任何解析;它不关心你想如何解析它,它只是返回NSData( Data) 或错误。

我有一个Parser触发 Plist 加载程序,获取Data然后使用新的 SwiftCodable协议解析它。

// A static function to try and find the plist file on bundle, load it and pass back data
static func loadBoard(completionHandler: @escaping (Board?, Error?) -> Void) {
     PListFileLoader.getDataFrom(filename: "data.plist") { (data, error) in
            if (error != nil) {
                print ("errors found")
                completionHandler(nil, error)
            }
            else {
                guard let hasData = data else {
                    print ("no data found")
                    completionHandler(nil, error)
                    return
                }
                do {
                    print ("found board")
                    let board = try decodeBoard(from: hasData) // Call a function that will use the decoder protocol 
                    completionHandler(board, nil)
                } catch {
                    print ("some other board error occured")
                    completionHandler(nil, error)
                }
            }
        }
}

然后将此解析后的数据返回给主程序,或者任何调用它的东西——例如;一个XCTest

我的 XC 测试:

func testBoardDidLoad() -> Board? {   // The return bit will show an error; but its fine without the return part
        BoardParsePlist.loadBoard { (board, error)  in
            XCTAssertNotNil(board, "Board is nil")
            XCTAssertNotNil(error, error.debugDescription)

// How do I now escape this and return flow to the normal application?
// Can I wrap this in a try-catch?
            }
        }

从分层视图来看,它看起来像这样。

XCTest
... Calls the parser  (completionBlock ...)
.... Parser calls the PListLoader  (completionHandler: ...)

现在感觉就像我被困在应用程序的其余部分中

BoardParsePlist.loadBoard { (board, error)  in
      // ... rest of the app now lives here?    
})

看来我正处于一个永无止境的completionBlocks 循环中。

你如何“逃脱”或突破完成块并将流程返回到主应用程序?

我不确定我是否解释正确,但希望能提供任何帮助。

感谢您的时间。

标签: swiftcompletionhandler

解决方案


不知道如何让 Swift 说“好的,完成块现在完成了——回到主程序。”

没有办法也没有必要这么说——它是自动发生的。

static func loadBoard(completionHandler: @escaping (Board?, Error?) -> Void) {
     PListFileLoader.getDataFrom(filename: "data.plist") { (data, error) in
          // completion handler code here
     }

     // "back to main"
}

在您的示例中,执行将以两种方式之一“返回主”,具体取决于是否PListFileLoader.getDataFrom异步运行。

如果它是同步运行的,则执行顺序为:

  • 你的应用调用loadBoard
  • 这叫getDataFrom
  • 依次调用其完成处理程序参数
  • 完成处理程序运行
  • “回到主要”运行

OTOH,如果getDataFrom是异步的(例如,因为它执行网络请求),则顺序将是:

  • 你的应用调用loadBoard
  • 这叫getDataFrom
  • 它开始异步工作并返回
  • “回到主要”运行
  • 在稍后的某个时间点,开始的工作getDataFrom完成,它调用完成处理程序参数
  • 完成处理程序运行

无论哪种方式,您都无需特别努力即可回到 main 。


推荐阅读