Open rnystrom opened 7 years ago
I love it!
Do we want the context to provide information about the change that we're preprocessing for?
Hmmm good question. You mean like if this is a new item vs existing? Or like the actual diff result (move, etc). The latter might be really tricky.
Are we prepared to accept that this will mean the data source and collection view are out-of-sync while preprocessing happens?
If built right, hopefully that shouldn't happen. We'll still have a single place where the data source is updated.
The only risk is that section controllers could change a property or something that effects numberOfItems
or w/e. There's all sorts of complications there tho, so hopefully we could encourage people to store data on the context object, then store it on main in preprocessingDidFinishWithContext:
.
There's probably more complications that I'm missing.
Do we want to provide an API to wait/perform a synchronous update? Maybe later?
Hmm, maybe later. Probably want to avoid any blocking API though, right? Locking up main would be nasty.
So where would this processor hook-in relative to the -objectsForListAdapter:
data source method?
We would basically like to have an "asynchronous" version of -objectsForListAdapter:
since this is where we map models --> view models.
@jessesquires order of ops would probably have to be:
-objectsForListAdapter:
-listAdapter: sectionControllerForObject:
dispatch_async
-runloop coalescing happens[UICollectionView performBatchUpdates:completion:]
-[IGListSectionController didUpdateToObject:]
still has to happen in batch update blockpreprocessingDidFinish
stuff before didUpdateToObject
, but also w/in this blockSo all the fetching-objects, didUpdateToObject:
, sectionControllerForObject:
still happens on main.
This sounds really nice. I just learned about dispatch_group_t
;)
For anyone wanting to work on this, please see the rough draft at #501.
This is a proposal to add an API that makes it easy to do expensive things (e.g. size text, file i/o) on a background queue from within a section controller before an update is applied.
Current situation
If you have expensive work to do before using your section controller, currently your only options are:
[adapter performUpdatesAnimated:YES completion:nil]
😢We use both of these solutions and still hit 60fps, but it is not easy.
API Design
IGListPreprocessingDelegate
IGListSectionController
similar to the scroll delegate calledpreprocessingDelegate
self
nil
by defaultIGListPreprocessingDelegate
The
IGListPreprocessingDelegate
will have 2 required methods:IGListPreprocessingContext
This is object is similar to the UIViewControllerContextTransitioning (should we name it IGListContextPreprocessing?). It's main duties:
preprocessingDelegate
infoobject
of the section controllerid value
object to store arbitrary dataCGSize
of some text, wrap it inNSValue
, and docontext.value = wrappedSize;
[context completePreprocessing]
to mark finishedConsiderations
Main thread affinity
Every public
IGListKit
API hasIGAssertMainQueue()
in it and I don't think we should remove any of that so we don't get into threading chaos. That means that when in-preprocessWithContext:
you can't do something like[self.collectionContext containerSize]
. We should strive to put all necessary background data on eachIGListPreprocessingContext
object.Concurrent work
Ideally, preprocessing should all be done concurrently, though we have to wait (non-blocking) until all of the work is finished before continuing. I think we could:
IGListPreprocessor
(?) object that inits a private, concurrent queuedispatch_group_t
nil
preprocessingDelegate
:dispatch_group_t
, object, etc) injectedNSMapTable
where context=>sectionController (use when finished)dispatch_group_enter
[sectionController.preprocessingDelegate preprocessWithContext:context]
dispatch_group_t
and callsdispatch_group_leave
inside-[IGListPreprocessingContext complete]
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{...}
NSMapTable
calling[sectionController.preprocessingDelegate preprocessingDidFinishWithContext:context]
IGListUpdatingDelegate and IGListAdapter APIs
Adding the concurrent step should coalesce other updates (but NOT execute updates!) until the preprocess work and the batch updates are all finished. Getting this working will be a little surgical:
IGListUpdatingDelegate
will need a block to execute before actually batch updating¯\_(ツ)_/¯
...Thoughts?
Curious to hear comments/questions/concerns on this. Specifically, how do you handle expensive sizing/fetching work with IGListKit (or elsewhere)?