gpt4 book ai didi

当完成处理程序明确使用@escaping 时,Swift 将完成处理程序闭包推断为默认的@nonescaping 而不是@escaping

转载 作者:行者123 更新时间:2023-11-28 13:49:01 26 4
gpt4 key购买 nike

swift 4.2,Xcode 10.1

在我正在处理的订单处理应用程序中,用户可以搜索已处理或提交的订单。发生这种情况时,它将检查是否有订单缓存,如果没有,它将使用异步 API 请求重新填充该缓存,然后再次检查缓存。

重新填充缓存的函数是一个私有(private)静态函数,它接受一个转义完成处理程序。每当我过去使用那个完成处理程序时,我所要做的就是在函数调用的末尾添加一个闭包。这是在我被指示尽可能缓存所有数据之前,并且只使用 API 来重新填充该缓存之前。从那时起,这个函数就变成了私有(private)函数,因为除了在这个类中,再也不需要从任何地方直接调用 API。

现在,当我将闭包直接放在函数调用之后时,它给我一个错误,基本上说我传递的是 @nonescaping 闭包而不是 @escaping 闭包:

"Cannot invoke 'getAndCacheAPIData' with an argument list of type '(type: Codable.Type, (String?) -> Void)', Expected an argument list of type '(type: CodableClass.Type, @escaping (String?) -> Void)'"

我以前从来没有明确声明一个闭包是@escaping,这似乎是不可能的。我怀疑因为该函数既是私有(private)的又是静态的,所以闭包被推断为@escaping 的方式存在某种问题。我超出了我的深度。我可以尝试将静态类转换为单例,但由于一个错误,我对重构一堆工作代码犹豫不决,直到我完全确定更改将解决问题,而我正在尝试做的是除非我改变我的方法,否则这是不可能的。

代码如下:

public static func fillSearchResultArray<ManagedClass: NSManagedObject>(query:String, parameters:[String], with type: ManagedClass.Type, completionHandler: @escaping (String?)->Void)
{
let codableType:Codable.Type
switch type
{
case is ClientTable.Type:
codableType = ClientData.self
case is OrderTable.Type:
codableType = OrderData.self
case is ProductTable.Type:
codableType = ProductData.self
default:
completionHandler("Unrecognized type.")
return
}
let fetchedData:[ManagedClass]
do
{
fetchedData = try PersistenceManager.shared.fetch(ManagedClass.self)
}
catch
{
completionHandler(error.localizedDescription)
return
}

if fetchedData.isEmpty
{
AppNetwork.getAndCacheAPIData(type: codableType)//error here
{(firstErrorString) in
//move search array data to the cache
if firstErrorString.exists
{
completionHandler(error)
}
else
{
AppNetwork.fillSearchResultArray(query: query, parameters: parameters, type: type)
{ errorString in
completionHandler(errorString)
}
}
}

return
}
else
{ ...

被调用函数的签名:

private static func getAndCacheAPIData <CodableClass: Any & Codable>(type:CodableClass.Type, completionHandler: @escaping (String?)->Void)

为什么 swift 将此闭包推断为默认的 @nonescaping 而之前它总是将其推断为 @escaping?

最佳答案

问题与闭包无关,与静态无关,与私有(private)无关。它与类型参数有关。您不能调用此方法:

private static func getAndCacheAPIData <CodableClass: Any & Codable>(type:CodableClass.Type, completionHandler: @escaping (String?)->Void)

使用类型为 Codable.Type 的变量.您传递的类型值必须是在编译时已知的具体类型。如果你想传递一个变量,你不能使用泛型。它必须是:

private static func getAndCacheAPIData(type: Codable.Type, completionHandler: @escaping (String?)->Void)

或者,您可以将其称为:

 AppNetwork.getAndCacheAPIData(type: Int.self) {(firstErrorString) in ... }

或其他一些在编译时已知的类型。

可能你真正想要的是这样的:

let completion: (String?) -> Void = {(firstErrorString) in ... }

switch ... {
case ...:
AppNetwork.getAndCacheAPIData(type: Int.self, completion: completion)
case ...:
AppNetwork.getAndCacheAPIData(type: String.self, completion: completion)
...

基本问题是协议(protocol)不符合自身,因此类型为 Codable.Type 的变量不满足 : Codable要求。这归结为您不能只调用的相同原因:

AppNetwork.getAndCacheAPIData(type: Codable.self) {...}

或者,您可以这样重构它:

private static func handleAPI<CodableClass: Codable>(type: CodableClass.Type) {
getAndCacheAPIData(type: type.self) { _ in ... the completion handler ..}
}


switch ... {
case ...:
AppNetwork.handleAPI(type: Int.self)
case ...:
AppNetwork.handleAPI(type: String.self)
...

旁注:Any &在这里是没有意义的。你只是说 <CodableClass: Codable> .

关于当完成处理程序明确使用@escaping 时,Swift 将完成处理程序闭包推断为默认的@nonescaping 而不是@escaping,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55011737/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com