在循环中放置completionHandler的位置?

问题描述:

我在这个函数中使用了completionHandler,但是它嵌套在几个for循环中(如下所示)。问题是现在每当它运行的循环被调用的处理程序,而我只希望处理程序在整个函数完成处理时通过Set。如果我把它放在循环之外,那么它会被调用得太早并且是空的。我应该在这里做什么?在循环中放置completionHandler的位置?

现在当我打印到控制台,以测试它打印: 设置项目1个 设置项目1,2 设置项目1,2,3等

struct RekoRequest { 




    public func getRekos(rekoType: rekoCategory, handler: @escaping (Set<String>) -> Void) { 

     var urls = [NSURL]() 
     var IDs = Set<String>() 


     TwitterRequest().fetchTweets(searchType: "things") { result in 


      guard let tweets = result as? [TWTRTweet] else {print("Error in getRekos receiving tweet results from TwitterRequest.fetchTweets"); return} 

      for tweet in tweets { 





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



       for match in matches { 


        if let url = match.url { 

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

         //Show the original URL 
         unwrappedNSURL.resolveWithCompletionHandler { 

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


          guard let urlDomain = expandedURL.host else { print("no host on expandedURL"); return } 

          switch urlDomain { 


          case "www.somesite.com": 

           let components = expandedURL.pathComponents 

           for component in components { 
            if component == "dp" { 
             guard let componentIndex = components.index(of: component) else {print("component index error"); return} 
             let IDIndex = componentIndex + 1 
             let ID = components[IDIndex] 

             //Filter out Dups and add to Set 
             IDs.insert(ID) 


             handler(IDs) 

             print(ID) //this prints multiple sets of IDs, I only want one when the function is finished completely 

            } 
           } 

           break; 

          default: 
           break; 
          } 
         } 


        } else { print("error with match.url") } 

       } //for match in matches loop 




      } //for tweet in tweets loop 


     } 
    } 







} 


// 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 completion(response?.url as NSURL? ?? originalURL) 
      } 
      .resume() 
    } 
} 
+1

为什么不把完成处理循环后? –

+0

当我把它放在循环后面时,我得到一个空集 – GarySabo

+0

@GarySabo你在哪里插入'IDs'集合? 'setOfIDs'是否是'IDs'? –

通话结束后,您的完成处理for循环。

for component in components { 
    if component == "dp" { 
     ... 
    } 
} 
handler(IDs) 

重要:handler应该叫 for循环,但TwitterRequest().fetchTweets()后关闭。


方法来处理空集

IDs被初始化为空集。只有在for循环中满足特定条件之后,才会将值插入到该集合中。如果这些条件不符合,则您的IDs组将为空。

如果这是不可取的,那么您将不得不更改您的完成处理程序或更改您的条件逻辑,以便始终获得非空集。

一种方法可能是在回调中使用可选集。喜欢的东西:

(Set<String>?) -> Void

如果IDs是空的,然后用nil回调,让你的调用代码处理nil组的可能性。

另一种方法可能是创建一个枚举来封装结果并在回调中使用它。喜欢的东西:

枚举

enum Result { 
    case success(Set<String>) 
    case failure 
} 

回调

handler: (Result) -> Void

使用

handler(.success(IDs)) 

// or 

handler(.failure) 

长途区号

getReckos(rekoType: .someType) { result in 
    switch result { 
    case .success(let IDs): 
     // Use IDs 
    case .failure: 
     // Handle no IDs 
    } 
} 
+0

谢谢,我可能不会说清楚它的正确性,但问题是我希望completionHandler发送它的结果是它的调用函数'RekoRequest()。getRekos(rekoType:sometype){result'当它遍历循环并且完成时,所以我只得到1个完成的Set ....截至目前我正在获得一个在循环中设置每个时间,即1,1和2,1 2和3等。 – GarySabo

+0

@GarySabo需要在for循环之外调用'handler'。这样,当循环结束时,你的'handler'将被'IDs'调用一次。 –

+0

@GarySabo在我的答案中的额外点试图解决你对空集的评论。可以用你现在写代码的方式创建一个空集。我的回答就如何处理潜在的空集提出了一些建议。 –