Pull to refresh is by far the most popular paradigm used in refreshing feed based views on an iOS device. First introduced by Loren Brichter of Tweetie, pull to refresh has made its way into just about every touch based device out there. Here’s the latest incarnation on the PS Vita (taken from @mattgemmell):

In fact, the idea was so good that Brichter decided to legally slap his name on it. Here’s a picture to help you better understand how this technology works (taken from gorumors.com):

Thankfully, Brichter doesn’t require you to obtain a license to use it shamelessly in your own app, bless him!
Current Solutions
Now, our own Miso app also uses this familiar pattern to refresh our views. But the task of integrating a 3rd party library into our app was not as idiot proof as we had hoped. Here are some popular libraries and why they made me feel uncomfortable:
- Enormego’s EGOTableViewPullRefresh
- Leah Culver’s PullToRefresh
Both libraries are essentially the same, with slight variations. Both libraries employs the use of 3 absolutely crucial methods of UIScrollViewDelegate:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
In enormego’s implementation, it is expected that the developer chain the scrollview’s delegate methods to the EGOTableViewPullRefresh to drive the refresh cycle’s core logic. This isn’t ideal because it forces the developer to implement those delegate methods regardless of the developer’s requirements. This solution could definitely be more self-contained and less intrusive on the clients code.
In Culver’s implementation, the problem is the opposite of enormego’s. The delegate methods are literally stolen from you in order to drive the logic. If you implemented them yourself, the entire thing breaks.
One last variant is to have the library become the UIScrollView’s delegate, but also chain every single method back to the original delegate. This is fine, except it becomes extremely laborious to maintain especially if your UIScrollView is actually a UITableView (which extends the protocol UIScrollViewDelegate), or if apple adds some more delegate methods.
Both libraries combine the logic and views into one class, perhaps for the sake of simplicity. What if I didn’t want a boring rotating arrow but an animating rainbow? There’s basically no way to customize the views without modifying the source code directly.
Introducing MSPullToRefreshController
Here’s my main beef with existing libraries:
- Too intrusive on my own code. I either play an essential part to making the library work, or the library will not work if I exercise some innocent freedoms.
- I couldn’t provide any custom views.
- I couldn’t provide any custom behaviors to the refresh cycle.
Instead of whining like I did, our very own CTO (Tim Lee) offered an actual solution to Beef #1: KVO (Key Value Observing). Specifically, to observe the contentOffset property of UIScrollViews.
[_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:NULL];
Using this trick, I was able to secretly offer pull to refresh features to any UIScrollView without having to become its delegate. With this simplification, I was able to quickly extend pull to refresh to all 4 edges of a UIScrollView, just in case you wanted to use the bottom side to load more, or if your feed was laid out in a carousel fashion.
Through the small exercise above, I saw MSPullToRefreshController as a self-contained object that handles nothing more except managing the logic involved pull to refresh cycles. It just didn’t make sense to add anything else to it, unless it enhanced the core behaviors. Translation: Beef #2′s solution doesn’t belong in this class.
To solve Beef #2 and #3 together, I decided to introduce the familiar delegate pattern to MSPullToRefreshController. It is through these methods that the developer will be able to customize behaviors and transform custom views to reflect each state in the refresh cycle.
Now I could easily write a wrapper around a MSPullToRefreshController instance and recreate any existing pull to refresh library by implementing 6 easy delegate methods! In fact, I’ve done just that in the included sample project on github!
Conclusion
Though this library is very simple, this marks my first step in to the world of open source (to reinforce our engineering culture per @nicolas). As @joshbuddy and @nesquena would say, 99% of open source projects stem from frustrations with existing solutions (or lack thereof). I hope somewhere someone will find this more suitable to his/her needs. Thanks for reading!
Good analysis on the existing libraries. And very interesting reflection. I liked the approach you have given to yours,’ll try;)
John, I like it a lot! Especially beacuse it is so easy to customize. Your first step into open source world is very successful indeed :)
Hi,
Very nice… May I ask a question? :)
Is it possible to use it (and how?) for navigating between uitableviews?
I mean when I use the pull function (up/down), instead of refreshing the current tableview, to load another one.
Briefly, I want to use the pull2refresh inside a “detail view” (that is a uitableview) and navigate into the different “detail views” (like a page control)…
Pingback: Open Source UI Control Adding Pull To Refresh On Any UIScrollview In Any Direction
Have you looked at https://github.com/Sephiroth87/ODRefreshControl ?
It does KVO on contentOffset too, but doesn’t satisfy beef(s) 2 & 3.
Just thought I’d mention it – taking a look at your version now.
A podspec is always nice too ;)