我有一个转义功能,一旦满足条件就可以完成:
private func xxxfastLoadLSecurityDescriptions(session: URLSession, mySymbols: [String]?, completion: @escaping(Bool) ->()) {
var counter = mySymbols?.count ?? 0
if counter == 0 { completion(false) }
var doubleCount = 0
// print("DESCRIPTION Starting Counter = \(counter)")
for symbolIndex in 0..<(mySymbols?.count ?? 0) {
guard let mySymbol = mySymbols?[symbolIndex] else { print("ERROR in fastLoadLSecurityDescriptions loop: No Symbol") ; continue }
guard let myGetDescriptionRequest = GenericDataRequest(dataToSend: [mySymbol], token: sessionToken, mgbRoute: MGBServerRoutes.retrieveSecurityDescriptionsRoute!)
else { print("Error Getting Security Description Request for \(mySymbol)") ; return }
mySessionSendMGBGenericRequest(session: session, request: myGetDescriptionRequest) { [weak self] success, serverMessage, returnUNISecurityDescription in
guard let self = self else { print("ERROR: self is nil") ; return }
if returnUNISecurityDescription?.count == 0 { print("nil returnUniSecurityDescription for \(mySymbol)") }
// print("DESCRIPTIONS COUNTER = \(counter)")
counter -= 1
var myDescription = UNISecurityDescription()
if returnUNISecurityDescription != nil, returnUNISecurityDescription?.count != 0 { myDescription = returnUNISecurityDescription![0] }
if myDescription.name == nil || myDescription.name == "" { print("Error: No Name for \(String(describing: mySymbol))") }
let myContainersIndices = self.myUNIList.singleContainer.indices.filter({ self.myUNIList.singleContainer[$0].ticker?.symbol == mySymbol })
var myPathArray = [IndexPath]()
for index in 0..<myContainersIndices.count {
self.myUNIList.singleContainer[myContainersIndices[index]].name = myDescription.name
self.myUNIList.singleContainer[myContainersIndices[index]].currencySymbol = myDescription.currencySymbol
self.myUNIList.singleContainer[myContainersIndices[index]].fillFundamentals() // --> Fills the outputs for sortdata
myPathArray.append(IndexPath(row: myContainersIndices[index], section: 0))
}
DispatchQueue.main.async {
self.filteredData = self.myUNIList.singleContainer
self.myCollection?.reloadItems(at: myPathArray)
}
if counter == 0 { // THIS IS TRUE MORE THAN ONCE WHILE IT SHOULD NOT BE TRU MORE THAN ONCE
if doubleCount > 0 { print("WHY!!!!") }
doubleCount += 1
print("DESCRIPTIONS counter = \(counter) -> \(self.myUNIList.listName) - symbols: \(String(describing: mySymbols?.count)) \n==================================================\n")
DispatchQueue.main.async { self.sortNormalTap("Load") { _ in self.displayAfterLoading() } }
completion(true)
return
}
}
}
}
要满足的条件是counter ==0。一旦满足,函数将完成并退出DispatchGroup。问题是计数器== 0多次为true(退出DispatchGroup时明显崩溃)。我真的不明白为什么会多次满足这个条件。代码是线性的,我看不出是什么原因造成的。任何帮助都非常感谢。这让我发疯。
答案 0 :(得分:1)
您的代码不是线程安全的,尤其是计数器。我使用相同的逻辑编写了一个示例,以说明这一点。如果运行几次,最终将达到发生问题的相同条件。
override func viewDidLoad() {
super.viewDidLoad()
let mySymbols: [Int] = Array(0...100)
for _ in 0..<100 {
xxxfastLoadLSecurityDescriptions(session: URLSession.shared, mySymbols: mySymbols) { (success, counter, doubleCount) in
print("Completed: \(success), Counter: \(counter), Double Count: \(doubleCount)")
}
}
}
private func xxxfastLoadLSecurityDescriptions(session: URLSession, mySymbols: [Int]?, completion: @escaping(Bool, Int, Int) ->()) {
var counter = mySymbols?.count ?? 0
if counter == 0 {
return completion(false, -1, -1)
}
var doubleCount = 0
for symbolIndex in 0..<(mySymbols?.count ?? 0) {
guard let _ = mySymbols?[symbolIndex] else {
print("Error")
continue
}
DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(Int.random(in: 50..<900))) {
counter -= 1
DispatchQueue.main.async {
self.view.layoutIfNeeded()
}
if counter == 0 {
if doubleCount > 0 {
// This will eventually print even though logically it shouldn't
print("*****Counter: \(counter), Double Count: \(doubleCount), Symbol Index: \(symbolIndex)")
}
doubleCount += 1
completion(true, counter, doubleCount)
return
}
}
}
}
输出:
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
*******************************************************************
***** Counter: 0, Double Count: 1, Symbol Index: 15
*******************************************************************
Completed: true, Counter: 0, Double Count: 2
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
*******************************************************************
***** Counter: 0, Double Count: 1, Symbol Index: 26
*******************************************************************
Completed: true, Counter: 0, Double Count: 2
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
Completed: true, Counter: 0, Double Count: 1
*******************************************************************
***** Counter: 0, Double Count: 1, Symbol Index: 57
*******************************************************************
Completed: true, Counter: 0, Double Count: 2
*******************************************************************
***** Counter: 0, Double Count: 1, Symbol Index: 3
*******************************************************************
Completed: true, Counter: 0, Double Count: 2
答案 1 :(得分:1)
最后,我通过使用DispatchGroup来解决此问题,如下所示(简化代码):
private func xxxFastLoadLSecurityDescriptions(session: URLSession, mySymbols: [String]?, completion: @escaping(Bool) ->()) {
let myGroup = DispatchGroup()
for symbolIndex in 0..<(mySymbols?.count ?? 0) {
myGroup.enter()
mySessionSendMGBGenericRequest(...) { [weak self] returnValue in
guard let self = self else { myGroup.leave() ; return }
// do some stuff with returnValue
myGroup.leave()
}
}
myGroup.notify(queue: .main, execute: {
completion(true)
})
}
我的问题是:是否有可能遇到与以前相同的问题?例如,说我有2个项目的循环。第一个项目进入组,并说第二个项目进入循环之前,异步调用返回一个值,第一个项目退出组。此时,在第二个项目进入该组之前,应触发.notify,并且完成第二个项目之前,completion(true)存在该函数。这可能吗?