ios - 调度组未按预期工作

标签 ios swift swift3 grand-central-dispatch

我设置了一个与此类似的功能并且它工作正常,但是我在 group.leave() 上崩溃了,在测试中我注意到 1 或 2 行打印 print("link =\(link)")print("getRekos processing over, handler is called") 之后打印,换句话说 group.leave () 在 for 循环完全完成之前被调用,或者某些迭代“泄漏”到组之外。是什么原因造成的?我已经发布了 getExpandedURL 和我的自定义扩展 resolveWithCompletionHandler 的代码,它们在 getRekos

中使用
 public func getRekos(rekoType: RekoCategory, handler: @escaping (Set<URL>) -> Void) {

        let setOfLinks = Set<URL>()
        let group = DispatchGroup() //Dispatch group code from: http://stackoverflow.com/questions/38552180/dispatch-group-cannot-notify-to-main-thread
        let backgroundQ = DispatchQueue.global(qos: .default)


        TwitterRequest().fetchTweets(searchType: rekoType) { result in

            guard let tweets = TWTRTweet.tweets(withJSONArray: result) as? [TWTRTweet] else { print("error in getRekos casting TwitterRequest().fetchTweets result as [TWTRTweet]"); return }

            for tweet in tweets {

                let text = tweet.text

                group.enter()
                backgroundQ.async(group: group,  execute: {

                    //Check tweet text if contains any URLs
                    self.getExpandedURLsFromText(text: text, handler: { (getExpandedLinksResult, error) in

                        if error != nil {
                            group.leave()
                        } else {

                            for link in getExpandedLinksResult {
                                print("link = \(link)")

                            }
                            group.leave()
                        }
                    })
                })
            } //for tweet in tweets loop
            group.notify(queue: backgroundQ, execute: {
                DispatchQueue.main.async {
                    print("getRekos processing over, handler is called")
                    handler(setOfLinks)
                }
            })
        }
    }


private func getExpandedURLsFromText(text: String, handler: @escaping ([URL], Error?) -> Void) {

    var linksInText = [URL]()
    let group = DispatchGroup() //Dispatch group code from: http://stackoverflow.com/questions/38552180/dispatch-group-cannot-notify-to-main-thread
    let backgroundQ = DispatchQueue.global(qos: .default)


    let types: NSTextCheckingResult.CheckingType = .link
    let detector = try? NSDataDetector(types: types.rawValue)

    guard let detect = detector else { print("NSDataDetector error"); return }

    let matches = detect.matches(in: text, options: .reportCompletion, range: NSMakeRange(0, (text.characters.count)))

    //CRITICAL CHECK - results were getting lost here, so pass back error if no match found
    if matches.count == 0 {
        handler([], RekoError.FoundNil("no matches"))
    }
        // Iterate through urls found in tweets
        for match in matches {

            if let url = match.url {

                    guard let unwrappedNSURL = NSURL(string: url.absoluteString) else {print("error converting url to NSURL");continue}

                    group.enter()
                    backgroundQ.async(group: group,  execute: {

                        //Show the original URL (ASYNC)
                        unwrappedNSURL.resolveWithCompletionHandler(completion: { (resultFromResolveWithCompletionHandler) in

                            guard let expandedURL = URL(string: "\(resultFromResolveWithCompletionHandler)") else {print("couldn't covert to expandedURL"); return}

                            linksInText.append(expandedURL)
                            group.leave()
                            //handler(linksInText, nil)
                        })
                    })


            } else { print("error with match.url") }
        } //for match in matches loop
            group.notify(queue: backgroundQ, execute: {
                DispatchQueue.main.async {
                    //print("getExpandedURLsFromText processing over, handler is called")
                    handler(linksInText, nil)
                }
            })
}

// Create an extension to NSURL that will resolve a shortened URL
extension NSURL
{
    func resolveWithCompletionHandler(completion: @escaping (NSURL) -> Void) {
        let originalURL = self
        let req = NSMutableURLRequest(url: originalURL as URL)
        req.httpMethod = "HEAD"

        URLSession.shared.dataTask(with: req as URLRequest){body, response, error in

            if error != nil {
                print("resolveWithCompletionHandler error = \(error)")
            }

            if response == nil {
                print("resolveWithCompletionHandler response = nil")
            }
            completion(response?.url as NSURL? ?? originalURL)
            }
            .resume()
    }
}

最佳答案

如果 matches.count > 1 中有多个匹配项 ( getExpandedURLsFromText )然后多次调用结果处理程序,使您的调度组逻辑中断。

清理你的逻辑。

您必须确保完成处理程序在成功时始终只被调用一次,每次错误都被调用一次。您在 guard 中的多个位置缺少对完成处理程序的调用声明。

关于ios - 调度组未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41537215/

相关文章:

ios - 如果设备被拔掉,解析无声推送通知不工作

ios - MKMapSnapshotter 内存崩溃 - UITableView 中的多次调用

ios - 用于解析 fetchAllIfNeededInBackground 的 Swift 2 语法

swift - CollectionView:scrollToItem、reloadData 和 Dispatch 队列

ios - UIWebView 和 WKWebView 的键盘 "done"按钮按下事件

ios - 在 NSManagedObjectsDidChangeNotification 创建无限循环后设置 lastModificationDate 属性

json - 快速获取JSON元素

ios - willChangeValue 相当于已删除的实体吗?

ios - swift : cannot subscript a value of type [Dictionary<String, AnyObject>] 具有字符串类型的索引

ios - 同步谷歌日历?