在Swift中,我有一个func递归复制文件夹,并使用异步调用。我想添加一个完成处理程序。有优雅的解决方案吗?
在我的macOS应用程序中,我使用的是一个smb库,它有用于上载和下载文件的API,但缺少一个内置机制来对整个文件夹执行相同操作,因此我尝试添加此功能。我编写了一对用于上载/下载的递归函数,它们工作得很好,但现在我想向在整个文件夹的复制操作结束时触发的方法添加一个完成处理程序。我已经添加了闭包作为参数,当递归调用该方法时,我将nil作为完成处理程序传递,因此我可以意识到完成处理程序仅为封闭文件夹激发。问题是,我使用的smb库使用异步调用,因此我的第一个实现检查处理程序是否为nil,如果不是,则触发它,因为主循环当然在递归调用操作结束之前完成。我想我能找到解决这个问题的办法,但我正在寻找一个快速而优雅的办法。我有一种强烈的感觉,有更多经验的人可以更容易地解决这个实现问题,并且以一种比我更简单的方式解决。我的代码很简单:在Swift中,我有一个func递归复制文件夹,并使用异步调用。我想添加一个完成处理程序。有优雅的解决方案吗?,swift,recursion,Swift,Recursion,在我的macOS应用程序中,我使用的是一个smb库,它有用于上载和下载文件的API,但缺少一个内置机制来对整个文件夹执行相同操作,因此我尝试添加此功能。我编写了一对用于上载/下载的递归函数,它们工作得很好,但现在我想向在整个文件夹的复制操作结束时触发的方法添加一个完成处理程序。我已经添加了闭包作为参数,当递归调用该方法时,我将nil作为完成处理程序传递,因此我可以意识到完成处理程序仅为封闭文件夹激发。问题是,我使用的smb库使用异步调用,因此我的第一个实现检查处理程序是否为nil,如果不是,则触
func downloadFolder(into url: URL, fromPath: String, completionHandler: ( (Error?) -> Void)?) {}
我有一个简单的循环,如果项目是文件夹,它会递归调用相同的函数,否则它会使用内置API下载项目。文件夹的层次结构在上载和下载时都会仔细地重新创建
谢谢您的帮助。我不确定在没有看到您的实现的情况下是否理解了您的方法,但希望我所写的可能会有所帮助。也许您可以使用
DispatchGroup
类,并为启动的每个异步任务调用其.enter()
,并在该任务完成时调用.leave()
。一旦.leave()
调用的数量匹配.enter()
后,.notify()
将执行一个异步块,您可以从中调用原始完成块
包装函数
这是您要调用的原始函数
func downloadFolder(into url: URL, fromPath: String, completionHandler: ( (Error?) -> Void)?) {
let group = DispatchGroup()
var error:Error?
_downloadFolder(group: group, into: url, fromPath: fromPath)
group.notify(queue: .main) {
completionHandler?(error)
}
}
递归函数
这是私有递归的
private func _downloadFolder(group: DispatchGroup, into url: URL, fromPath: String) {
print("Entering:", fromPath)
group.enter()
let filesToCopy = Int.random(in: 1...3)
//Base case: No more subfiles
//Simulating in a weird fashion
if filesToCopy == 0 || fromPath.count > 10 {
print("Done here:", fromPath)
//Call this when your async task is finished, like you would a completion handler.
group.leave()
}else{
//Recursive case: There's still files to copy on this path.
for i in 0..<filesToCopy {
let subPath = "\(fromPath)/\(i + 1)"
_downloadFolder(group: group, into: url, fromPath: subPath)
}
group.leave()
}
}
考虑联合框架?我现在什么都用它。谢谢!它看起来很棒,我一定会努力学习它。不幸的是,我的应用程序是针对macOS的,我希望至少保留Sierra和更高版本。。。我的理解是,它是针对卡塔琳娜和后来。。。非常感谢你的帮助!非常感谢克里斯,回答得很好!你甚至不看我的实现就解决了我的问题太棒了!我将编辑我的问题,并插入更多的背景信息,使文章对其他用户更有用。再次感谢!
downloadFolder(
into: URL(string: "https://www.google.com")!,
fromPath: "Root"
) { (err) in
if let err = err {
print(err)
}else{
print("Finished copying with no errors.")
}
}