简体   繁体   English

Swift 代码在不应该运行的时候运行了两次

[英]Swift Code Running Twice When It Should Not

I have an escaping function, which completes once a condition is met:我有一个转义函数,一旦满足条件就会完成:

  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
                }
            }
        }
    }

The condition to be met is counter == 0. Once this is met, the function completes and exits a DispatchGroup.要满足的条件是 counter == 0。一旦满足,该函数完成并退出 DispatchGroup。 The problem is that counter == 0 is true multiple times (with obvious crash in exiting the DispatchGroup).问题是 counter == 0 多次为真(退出 DispatchGroup 时明显崩溃)。 I really cannot understand why this condition is met more than once.我真的无法理解为什么不止一次满足这个条件。 The code is pretty linear and I cannot see what causes this.代码非常线性,我看不出是什么原因造成的。 Any help is very appreciated.非常感谢任何帮助。 This is running me crazy.这让我发疯。

You're code isn't thread safe, the counter in particular.您的代码不是线程安全的,尤其是计数器。 I wrote an example using your same logic to show illustrate this.我使用您的相同逻辑编写了一个示例来说明这一点。 If you run it a few times, you will eventually hit the same condition in which your issue is happening.如果您多次运行它,您最终会遇到与您的问题发生相同的情况。

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
            }
        }
    }
}

Output:输出:

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

At the end I solved this by using DispatchGroup as follows (simplified code):最后我通过使用 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)
    })
}

My question is: is it possible that I run into the same problem as before?我的问题是:我有可能遇到和以前一样的问题吗? For example, say I have a loop for 2 items.例如,假设我有 2 个项目的循环。 The firs item enters the group and say the before the second item enters the loop the async call returns a value and the first item exits the group.第一个项目进入组并说在第二个项目进入循环之前异步调用返回一个值,第一个项目退出组。 At this point, before the second item enters the group the .notify should be triggered and completion(true) exists the function before the second item is processed.此时,在第二项进入组之前,应该触发 .notify 并且在处理第二项之前完成(true) 存在函数。 Is this possible?这可能吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Swift中运行两次的用于检查数据和存储数据的代码 - Code for checking data and storing data running twice in Swift Swift:当SearchBar处于活动状态时,应按两次Back按钮 - Swift: Back button should be pressed twice while SearchBar is active 仅在Swift中运行测试代码 - Running code only for tests in Swift Swift 4错误在扩展中运行代码 - Swift 4 Error Running Code in Extension Swift - 完成处理程序代码未运行 - Swift - Completion handler code not running 当遵循MVC设计模式时,UIViewController类文件中应包含哪些代码? -Swift4 - When following MVC design pattern what code should be in the UIViewController class file? - Swift4 在Swift中,如果将帧速率最大化作为目标时可行的选择,是否应该在prepareForSegue或viewDidLoad中运行VC初始化代码? - In Swift, should I run VC initialization code in prepareForSegue or in viewDidLoad if it is a viable option when maximizing frame rate is the goal? 在Swift中运行Firebase时出错 - Error when running Firebase in Swift Xcode编译快速代码太慢,因为它编译两次 - Xcode compiles swift code too slow because of it compiles twice 我应该在哪里将UI代码放在Swift中? - Where should I put UI Code in Swift?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM