user1960169
user1960169

Reputation: 3663

scrollViewDidScroll call multiple times in swift

I have a UIScrollView inside tgat I have a UITableView. I have disabled scrolling for the UITableView So I just want to check whether my scroll view has reached to the bottom if so call load more table function. So for that I did something like this.

func scrollViewDidScroll(scrollView: UIScrollView) {



        if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
            //reach bottom
            self.startRec+=10
            self.jsonParser()
        }

        else if (scrollView.contentOffset.y < 0){
            //reach top
        }

        else if (scrollView.contentOffset.y >= 0 && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)){
            //not top and not bottom
        }
}

But my problem is it seems its calling this jsonParser()multiple times when I scrolled it. How can I solve this problem? Please help me. Thanks

Upvotes: 1

Views: 3292

Answers (3)

Moshe
Moshe

Reputation: 58097

The UIScrollViewDelegate methods get called multiple times as the user initiates, drags, and then lifts their finger from their device. You should probably check for an existing parser, and if there is one simply return instead of running a new one.

Inside of jsonParser():

func jsonParser() {

   if /* JSON is in process */ {
      return
   }

   // process then clean up

}

This will prevent your code from firing multiple times. Just make sure to manage your state correctly.

Upvotes: 1

Jacob Boyd
Jacob Boyd

Reputation: 680

Do you have a reason for subviewing a tableview in a scroll view? I mean table views are a subclass of scrollview and one of the major advantages of using a tableView is the dequeueCell method.

You could get better performance out of your application by just placing the tableview where you want it in your view controller and then using the delegate function

func tableView(_:willDisplayCell:forRowAtIndexPath:)

inside of this delegate method you could call your jsonParser if the cell coming into view is say, 3-5 indexes from the end of your datasource

func tableView(_:willDisplayCell:forRowAtTndexPath:) {
    if (indexPath.row == resultsArray.count - 3) {
        //load your extra data

        self.startRec+=10
        self.jsonParser()
    }

Of course you could change that number 3 to whatever you wish, but that would create a situation where your jsonParser() will only be called whenever the table is getting close to the end of your data source, and you will get the benefits of using the dequeue cell.

Here is the link to Apple's docs if you want it for reference : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath:

I used this same approach to a collection view I was creating for infinite scrolling.

-(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.item == self.arrCollectionData.count - 5) {
        [self.myWebService startWebServiceRequestWithURL:_currentURL];
    }
} 

Upvotes: 0

mikepj
mikepj

Reputation: 1338

You could add an instance variable to the class to keep track of when jsonParser is running. If it's already running, then return without doing anything. You would need to increment startRec only if the jsonParser isn't running yet as well. Something like:

func incrementAndParseJSON() {
   if self.alreadyRunning == false {
       self.alreadyRunning = true
       self.startRec += 10
       self.jsonParser()
       // Presumably, jsonParser is asynchronous, so set self.alreadyRunning = false after it's done.
   }
}

Upvotes: 0

Related Questions