iosswiftloops

How to loop API Calls Swift after parsing data


I'm currently making an API call to return a bunch of JSON data, parsing it, and then sorting it based on a few different criteria. After the JSON data is parsed (it pulls back a bunch of recipes), it's filtered through a few functions that trim the results pool to more accurately fit what the user requested (ie. User only wants recipes that take less than 30 minutes to prepare) .

Sometimes after all these filters there are no more recipes left! - When that happens id like to re-call the API again automatically. I'm not really sure how to do this without creating an infinite loop of some sort - code below:

    SLApiCall.sharedCall.callGetApi(SearchUrl, params: dictPara) { (response, err ) -> () in
        
        var data = response!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        var localError: NSError?
        var jsonobj: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) as? NSDictionary

        var arrTemp : NSArray = (jsonobj?.valueForKey("matches") as? NSArray)!
        
        var totalMatches = jsonobj.valueForKey("totalMatchCount") as! Int
        User.currentUser.setTotalRecipesMatched(totalMatches)
        let (max, min) = User.currentUser.ingredientsCountBasedOnLazyOption()
        
        printTimeElapsedWhenRunningCode("test12345") {
            
            self.arrRecipes = self.SortingArray(arrTemp.arrayByReplacingNullsWithBlanks(), maxLimit: max, minLimit: min)
        // This is where all the sorting happens, if this returns an empty array I want to re-call the method. 
        
        }
        
        User.currentUser.setList(self.arrRecipes!, param: theJSONText as! String)

        self.assignDemoData()

    }

Solution

  • A possible solution for your problem is using repeat-while using a semaphore to employ a wait for the asynchronous call. Be aware though that, trying to do this in main thread might block your UI, so might want it to do in a secondary thread/queue. Also updating UI, etc must be done in main thread:

    repeat{
    
      dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
      var gotData  = false
    
      SLApiCall.sharedCall.callGetApi(SearchUrl, params: dictPara) { (response, err ) -> () in
    
        var data = response!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        var localError: NSError?
        var jsonobj: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) as? NSDictionary
    
        var arrTemp : NSArray = (jsonobj?.valueForKey("matches") as? NSArray)!
    
        var totalMatches = jsonobj.valueForKey("totalMatchCount") as! Int
        User.currentUser.setTotalRecipesMatched(totalMatches)
        let (max, min) = User.currentUser.ingredientsCountBasedOnLazyOption()
    
        printTimeElapsedWhenRunningCode("test12345") {
    
          self.arrRecipes = self.SortingArray(arrTemp.arrayByReplacingNullsWithBlanks(), maxLimit: max, minLimit: min)
          // This is where all the sorting happens, if this returns an empty array I want to re-call the method.
          if(self.arrRecipea.count){
            gotData = true
    
          }
    
        }
    
        User.currentUser.setList(self.arrRecipes!, param: theJSONText as! String)
    
        self.assignDemoData()
    dispatch_semaphore_signal(sem)
      }
    
      //Wait until the block is called
      dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); //Note- have a meaningful timeout here
    
    }while (gotData != true)