如何将 Swift 到 return 中的 completionBlock 转义到正常的应用程序流程?
How do you escape a completionBlock in Swift to return to normal application flow?
让我陷入 Swift 的其中一件事是我程序中永无止境的 completionBlocks
链;而且我不确定如何让 Swift 说 "Ok, the completion block is now done -- come back to the main program."
在我的项目中,我正在编写一个简单的 board/card 游戏,它从一个非常小的 plist 加载数据。
我写了一个相当简单的 Plist 加载器,它加载 plist 并通过 completionBlock 返回 Data
。它不做任何解析;它不关心你想如何解析它,它只是 returns 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)
}
}
}
}
然后 return 将这个解析后的数据发送到主程序,或者调用它的任何东西——例如;一个 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?
})
看来我正处于 completionBlock
的永无止境的循环中。
你如何"escape"或突破完成块并return流回主应用程序?
我不确定我是否解释正确,但希望得到任何帮助。
感谢您的宝贵时间。
not sure how to get Swift to say "Ok, the completion block is now done -- come back to the main program."
没有办法也不需要这么说 - 它会自动发生。
static func loadBoard(completionHandler: @escaping (Board?, Error?) -> Void) {
PListFileLoader.getDataFrom(filename: "data.plist") { (data, error) in
// completion handler code here
}
// "back to main"
}
在您的示例中,执行将以两种方式之一获得 "back to main",具体取决于 PListFileLoader.getDataFrom
是否为 运行 异步。
如果是运行同步,则执行顺序为:
- 您的应用调用
loadBoard
- 这会调用
getDataFrom
- 依次调用其完成处理程序参数
- 完成处理程序运行
- "back to main" 运行
OTOH,如果 getDataFrom
是异步的(例如,因为它进行网络请求),顺序将是:
- 您的应用调用
loadBoard
- 这会调用
getDataFrom
- 开始异步工作,returns
- "back to main" 运行
- 在稍后的某个时间点,
getDataFrom
开始的工作完成,它调用完成处理程序参数
- 完成处理程序运行
无论哪种方式,您都可以轻松回到主界面。
让我陷入 Swift 的其中一件事是我程序中永无止境的 completionBlocks
链;而且我不确定如何让 Swift 说 "Ok, the completion block is now done -- come back to the main program."
在我的项目中,我正在编写一个简单的 board/card 游戏,它从一个非常小的 plist 加载数据。
我写了一个相当简单的 Plist 加载器,它加载 plist 并通过 completionBlock 返回 Data
。它不做任何解析;它不关心你想如何解析它,它只是 returns 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)
}
}
}
}
然后 return 将这个解析后的数据发送到主程序,或者调用它的任何东西——例如;一个 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?
})
看来我正处于 completionBlock
的永无止境的循环中。
你如何"escape"或突破完成块并return流回主应用程序?
我不确定我是否解释正确,但希望得到任何帮助。
感谢您的宝贵时间。
not sure how to get Swift to say "Ok, the completion block is now done -- come back to the main program."
没有办法也不需要这么说 - 它会自动发生。
static func loadBoard(completionHandler: @escaping (Board?, Error?) -> Void) {
PListFileLoader.getDataFrom(filename: "data.plist") { (data, error) in
// completion handler code here
}
// "back to main"
}
在您的示例中,执行将以两种方式之一获得 "back to main",具体取决于 PListFileLoader.getDataFrom
是否为 运行 异步。
如果是运行同步,则执行顺序为:
- 您的应用调用
loadBoard
- 这会调用
getDataFrom
- 依次调用其完成处理程序参数
- 完成处理程序运行
- "back to main" 运行
OTOH,如果 getDataFrom
是异步的(例如,因为它进行网络请求),顺序将是:
- 您的应用调用
loadBoard
- 这会调用
getDataFrom
- 开始异步工作,returns
- "back to main" 运行
- 在稍后的某个时间点,
getDataFrom
开始的工作完成,它调用完成处理程序参数 - 完成处理程序运行
无论哪种方式,您都可以轻松回到主界面。