비슷한 기능을 설정했지만 제대로 작동하지만 group.leave()
여기에서 충돌하고 테스트에서 인쇄 라인 중 하나 또는 두 개가 print("getRekos processing over, handler is called")
이후에 인쇄되고 있음을 확인했습니다. 즉, group.leave()
이 for 루프를 완전히 완료하기 전에 호출되거나 일부 반복이 그룹 외부로 "누출"됩니다. 무엇이 이것을 일으킬 수 있습니까? 나는 getExpandedURL
에 대한 코드를 게시 한 및 getExpandedURLsFromText
다음 결과 핸들러가 호출 여러 번에 여러 일치 (matches.count > 1
)이있는 경우 내 사용자 지정 확장 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()
}
}
내가 알아낼 수있는 유일한 이유는'handler ([], RekoError.FoundNil ("no matches"))''다음에'return'을하지 않는다는 것입니다. 따라서 이론적으로'handler (...) '에 대한 두 번째 호출을 배치 할 수 있습니다. 그러나 'match in matches'루프가 트리거되지 않아야하므로 귀하의 경우에는 안됩니다. – shallowThought
고마워, 그리고 그 블록 (예 :'matches.count == 0 {')이 실행되지 않는다면, 나는 그럴 것이라고 생각한다. – GarySabo
또한'handler'가 전혀 호출되지 않을 때 따라서 그룹은 결코 알리지 않습니다. – Sulthan