2016-12-15 3 views
0

Я использую функцию завершения в этой функции, однако он вложен в несколько циклов (ниже). Проблема заключается в том, что обработчик, где он теперь вызывается каждый раз, когда цикл находится в циклах, тогда как я хочу, чтобы обработчик прошел только в Set, когда вся функция завершила обработку. Если я поместил его за пределы цикла, то он будет вызван слишком рано и пуст. Что мне здесь делать?Где разместить завершениеHandler, когда внутри петли?

Прямо сейчас, когда я печатаю на консоль, чтобы проверить его печатает: Устанавливаемая 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 Где вы вставляете в набор идентификаторов? Предполагается ли 'setOfIDs' быть' идентификаторами'? –

ответ

0

Вызов обработчика завершения по очереди для цикла.

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

Важно:handler следует назвать вне из за цикл, но в пределахTwitterRequest().fetchTweets() заднего закрытия.


подходы к обработке пустого набора

Вашего IDs в настоящее время инициализируется пустым множество. Только после выполнения определенных условий в вашем цикле for значения вставляются в этот набор. Если эти условия не выполняются, то ваш набор IDs будет пустым.

Если это нежелательно, вам придется либо внести изменения в обработчик завершения, либо изменить условную логику, чтобы вы всегда получали непустой набор.

Один из подходов может заключаться в том, чтобы в вашем обратном вызове был установлен дополнительный набор. Что-то вроде:

(Set<String>?) -> Void

Если IDs пусты, то обратный вызова с nil и вашим кодом вызова обрабатывать возможность nil набора.

Другим подходом может быть создание перечисления для инкапсуляции вашего результата и использования этого в вашем обратном вызове.Что-то вроде:

Enum

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

Спасибо, я не могу сформулировать его правильно, но проблема в том, что я хочу, чтобы completeHandler отправил его результат для его вызывающей функции 'RekoRequest(). getRekos (rekoType: sometype) {result in', когда он повторяется в цикле и закончен, так что я получаю только 1 завершенный Set .... на данный момент я получаю Установите каждый раз через цикл, т.е. 1, 1 и 2, 1 2 и 3 и т. Д. – GarySabo

+0

@GarySabo «Обработчик» должен вызываться вне цикла for. Таким образом, когда цикл закончен, ваш обработчик будет вызываться один раз с идентификаторами. –

+0

@GarySabo Дополнительные пункты в моем ответе пытаются адресовать ваш комментарий о пустом наборе. Пустой набор возможен с тем, как вы в настоящее время записываете свой код. В моем ответе вы найдете несколько предложений о том, как обращаться с потенциальным пустым множеством. –

Смежные вопросы