我正在尝试使用来自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
}
}
答案 0 :(得分:4)
似乎您打过一次电话
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)