如何在 Swift 中转义完成块以返回正常的应用程序流程?

Posted

技术标签:

【中文标题】如何在 Swift 中转义完成块以返回正常的应用程序流程?【英文标题】:How do you escape a completionBlock in Swift to return to normal application flow? 【发布时间】:2020-05-15 20:08:13 【问题描述】:

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

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

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

我有一个Parser,它会触发 Plist 加载程序,获取 Data,然后使用新的 Swift Codable 协议对其进行解析。

// 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

我的 XCTest:

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 的永无止境的循环中。

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

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

感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

不知道如何让 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 开始的工作完成,它调用完成处理程序参数 完成处理程序运行

无论哪种方式,您都无需特别努力即可返回主目录。

【讨论】:

感谢您的帮助。我认为问题是我在 XCTest 中使用它并且想要加载 plist 一次且仅一次,因此我不必每次测试都在内存中重新创建它,我的“概念”是加载一个函数内存中的板,然后将其传递给我需要的每个 XCTestCase。但现在我明白了,感谢您的帮助

以上是关于如何在 Swift 中转义完成块以返回正常的应用程序流程?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JavaScript 中转义单引号 ( ' )? [复制]

如何在 freemarker 模板处理中转义 unicode 符号?

如何在降价表的代码语句中转义管道字符?

如何在 Pyspark 的动态列列表中转义列名

如何在 URL 中转义哈希字符

iOS中转义后的html标签如何还原