ios - 将采用转义闭包的闭包传递给接受该类型闭包的函数的问题

标签 ios swift closures y-combinator

在旧的 swift 世界中(我相信是 2.0)我有以下 Y 组合器实现

func Y<T, R>( f: (T -> R) -> (T -> R) ) -> (T -> R) {
    return { (t: T) -> R in
        return f(self.Y(f))(t)
    }
}

我会在别处调用 Y 梳来创建递归闭包,如下所示:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
let repeatClosure = self.Y {
    (f: () -> () ) -> (() -> ()) in
    return {
        if self.responses_received != responses_expected {
            dispatch_after(delayTime, dispatch_get_main_queue()) {                         
                // Resend 
                NSNotificationCenter.defaultCenter().
                    postNotificationName(sendData, 
                    object: nil, userInfo: dataToSend)

                f()
            }
        } else {
            print("Completed!")
            self.responses_received = 0
        }
    }
}

repeatClosure()

想法是当“sendData”通知的观察者收到他的回复时,他会向包含我的 Y 组合器和重复闭包的类发送通知。一旦“sendData”通知的所有观察者实例都收到了它们的数据,

self.responses_received == responses_expected

将为真,我们不会再次调用 f()。

现在,我的问题是向 Swift 3.0 的转换迫使我在 Y 的定义中明确声明 'f' 的类型为 @escaping,如下所示:

func Y<T, R>( _ f: @escaping ((T) -> R) -> ((T) -> R) ) -> ((T) -> R) {
    return { (t: T) -> R in
        return f(self.Y(f))(t)
    }
}

然后将我的重复闭包转换为相同的类型。很好,我理解@escaping 和@noescape 之间的区别以及为什么我的代码需要它。但是,在尝试构建时,我收到有关类型不匹配的编译错误:

Cannot convert value of type '(@escaping () -> ()) -> (() -> ())' 
to expected argument type '(() -> ()) -> (() -> ())'

我创建了一个简单的示例闭包只是为了测试它会给出相同的错误:

let innerClosure = { (f: @escaping ()->()) -> (()->()) in
    return {}
}

let repeatClosure = self.Y(innerClosure)

而以下没有问题:

let innerClosure = { (f: ()->()) -> (()->()) in
    return {}
}

let repeatClosure = self.Y(innerClosure)

我从 fixit 那里得到了强制转换为类型的建议,没有 @escaping 标签。这可以编译,但感觉不对,而且我还没有实际测试过该转换是否会在运行时真正起作用。

我在这里错过了什么?

最佳答案

您的 Y 函数应具有以下签名:

func Y<T, R>(_ f: @escaping (@escaping (T) -> R) -> ((T) -> R)) -> ((T) -> R)

因为它接受一个转义函数,而这个转义函数本身也需要一个转义函数。

当您调用 Y 时,闭包应该以:

self.Y { (f: @escaping () -> ()) -> (() -> ()) in

请注意,此@escaping 对应于Y 签名中的第二个 转义。这是导致编译器错误的 @escaping 不匹配。

其余大部分应该自行解决(一旦您将 Dispatch 和 NSNotificationCenter 调用更新为 Swift 3)。

关于ios - 将采用转义闭包的闭包传递给接受该类型闭包的函数的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39643834/

相关文章:

ios - 如何将 AVCaptureVideoPreviewLayer 旋转 90 度以在 iOS11 中更正它?

ios - 使用 alamofire 下载文件获取代码 -1001

javascript - 调用 apply 到包装(匿名)函数

javascript - Nodejs 闭包变量未在模块中更新

javascript - 如何修复我的 jQuery 代码中的闭包错误

ios - 在第一次运行时加载不同的 View

ios - 删除特定表格 View 单元格的手势

swift - Rx swift : manage object updates in the app

iOS MapBox - 在 imageForAnnotation 方法中获取注释标题

ios - swift iOS : How to refactor a lot of conditions for if statement?