swift - 在异步函数在 Swift 中完成执行后,在尾随闭包之外获取一个完全填充的数组

标签 swift asynchronous

我正在尝试使用 extractProperties() 函数的异步调用结果填充 finalArray。

class ViewController: UIViewController {

var finalArray: [SingleRepository] = []

let extractor = Extractor()

override func viewDidLoad() {
    super.viewDidLoad()

    print("Starting the program... ")

    extractor.extractProperties { object, error in
        guard let object = object else {
            print("Extractor did not reutrn data")
            return
        }
        self.finalArray.append(object)
        print("Appended successfully --- \(self.finalArray.count) --- inside the trailing closure")

    }

    print("Size of the array --- \(self.finalArray) --- outside the trailing closure")


}

问题是我无法让完全填充的 finalArray 在尾随闭包范围之外工作! 输出日志:

    Starting the program... 
Size of the array --- [] --- outside the trailing closure
Appended successfully --- 1 --- inside the trailing closure
Appended successfully --- 2 --- inside the trailing closure
Appended successfully --- 3 --- inside the trailing closure
.
.
.
Appended successfully --- 300 --- inside the trailing closure

我知道为什么首先执行来自外部的 print 语句,但我永远无法获得包含所有 300 个对象的完全填充数组。

请注意以下帖子没有解决我的问题:Run code only after asynchronous function finishes executing

我什至通过编写以下函数尝试解决该帖子中的问题:

func constructingFinalArray(completionBlock: @escaping ([SingleRepository]) -> Void) {
        var fArrray: [SingleRepository] = []
        extractor.extractProperties { data, error in
            guard let data = data else {
                print("Extractor did not reutrn data")
                return
            }
            fArrray.append(data)
            completionBlock(fArrray)
        }
    }

并在 viewDidLoad() 中调用它,如下所示,但令人困惑的是我得到了相同的结果,并且数组逐个元素地填充,因此永远无法从尾随闭包中访问完全填充的数组!

constructingFinalArray { array in
        print("array size from constructingFinalArray function: \(array.count) ")
    }

输出:

    Starting the program... 
array size from constructingFinalArray function: 1 
array size from constructingFinalArray function: 2 
array size from constructingFinalArray function: 3
.
.
.

extractProperties 被准确地调用了 300 次,有时它没有返回任何日期(错误)。

    // Class to extract the required properties and
// provide ready to use object for ViewController
class Extractor {
    private let client = RepoViewerAPIClient()
    private var allURLs: [RepositoryURL] = []
    var allRepositories: [SingleRepository] = []


    // Method to extract all the required properties
    // compromising of 2 asynchrounous call, (nested asynch call)
    // one to get the urls and another call within the first call to extract all the propreties
    func extractProperties(completionHandler: @escaping (SingleRepository?, RepoViewerErrors?) -> Void) {
        // implementation of nested asynchronous calls are deleted to shorten the question length 


    }

}

最佳答案

好像你调用一次之后

extractor.extractProperties {
    ...
}

闭包被调用恰好 300 次,但有时它可能不返回任何数据。

在这种情况下,您可以采用这种方法。

extractor.extractProperties { object, error in
    serialQueue.async { [weak self] in

        count += 1

        guard count < 300 else  {
            self?.didCompletePopulation()
            return
        }

        guard let object = object else {
            print("Extractor did not reutrn data")
            return
        }

        self?.finalArray.append(object)

    }
}

func didCompletePopulation() {
    // be aware, this is not called on the main thread
    // if you need to update the UI from here then use the main thread
    print("Final array is populated \(self.finalArray)")
}

它是如何工作的?

闭包的主体被包装到另一个通过串行队列执行的闭包中。这样我们就可以确保共享资源(finalArray 和计数)被安全访问。

serialQueue.async { [weak self] in
    ...
}

接下来,闭包的每次执行都会将 count 递增 1

然后我们确保计数小于 300,否则我们停止执行闭包并调用 didCompletePopulation()

guard count < 300 else  {
    self?.didCompletePopulation()
    return
}

我们检查结果是否包含正确的值,否则我们停止执行当前闭包

guard let object = object else {
    print("Extractor did not reutrn data")
    return
}

最后我们将新元素添加到数组中

self?.finalArray.append(object)

关于swift - 在异步函数在 Swift 中完成执行后,在尾随闭包之外获取一个完全填充的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51921058/

相关文章:

swift - 为什么没有 Swift 等价于向 View 添加操作?

ios - 点击一个单元格也会影响其他单元格

swift - FileManager.url 中的 appropriateFor 参数是什么(对于 :in:appropriateFor:create:)?

ios - 应用程序取消并出现 fatal error : unexpectedly found nil while unwrapping an Optional value

javascript - 设置 bcrypt 以与 Passport 和 async-await Node.js 库配合使用

ruby-on-rails - Rails - 异步发送所有带有 delayed_job 的电子邮件

node.js - 使用异步和请求包进行多个 API 调用 (NodeJS/Express)

swift - 无法将 NSTaggedPointerString 类型的值转换为 NSDictionary

javascript - jQuery 多个延迟在返回之前解析和处理

python - 将 asyncio 与多处理结合起来会出现什么样的问题(如果有的话)?