派遣组未按预期工作

时间:2017-01-08 19:58:28

标签: 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()
    }
}

1 个答案:

答案 0 :(得分:1)

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

清理你的逻辑。

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