2016-12-15 2 views
0

私はこの関数で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'であると思いますか? –

答えて

0

は後に完了ハンドラを呼び出しますforループ。

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

重要:handlerは、forループの外と呼ばれるが、TwitterRequest().fetchTweets()末尾閉鎖されるべきです。

あなたIDsが空集合に初期化されている空のセットを処理する


アプローチ。 forループ内の特定の条件を満たした後でのみ、値がこ​​のセットに挿入されます。これらの条件が満たされない場合、IDsセットは空になります。

これが望ましくない場合は、完了ハンドラを変更するか、条件付きロジックを変更して常に空でないセットを取得する必要があります。

1つの方法では、コールバックにオプションのセットを含めることができます。ような何か:

(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){結果がループを反復処理されて終了するので、完了したSetを1つだけ取得します。ループごとに1、1、2、1、2、3などを設定します。 – GarySabo

+0

@GarySabo 'handler 'はforループの外で呼び出す必要があります。そうすれば、ループが終了すると 'ハンドラー'が 'ID'で一度呼び出されます。 –

+0

@GarySabo私の答えの追加ポイントは、空のセットについてのあなたのコメントを解決しようとしています。あなたのコードが書かれている方法で、空のセットが可能です。私の答えは、潜在的な空のセットを扱う方法に関するいくつかの提案を提供します。 –

関連する問題