Question

• My general goal

My goal is

  1. to load some data in a view-based Table View and perform some operations (for the display of the Table View)
  2. at the end of loading to scroll to the top of the Table View.

• Some more details

During the loading, a lot of actions are performed. More precisely, the Table View is view-based and in each row, there is a Text View whose content is bound to some property. The delegate method - (void)textDidChange: is implemented (to enlarge the Text View if necessary). I have also subclassed NSTextView and overwritten the method - (void)setString: for the same purpose.

So, when the text is loaded to the rows of the Table View, a lot of actions are performed.

• The code

My code works with afterDelay:0 (scrolling to the top happens) but not without.

// works
- (void)updateTheController
{
    [super updateTheController] ;
    self.theCollectionView.representedObject = self.representedObject ;
    [self.theCollectionView performSelector:@selector(goToTop) 
                                 withObject:nil 
                                 afterDelay:0] ;
}

but

// does not work
- (void)updateTheController
{
    [super updateTheController] ;
    self.theCollectionView.representedObject = self.representedObject ;
    [self.theCollectionView goToTop] ;
}

• My question

I am wondering if there is a better solution or an explanation. I remember something with CATransaction but I don't know if it will work here, and I don't remember which method to call (and why), [CATransaction commit], [CATransaction commit]?

My question could be: By what can I replace afterDelay:0 and why do I need it?

Thanks!!

Was it helpful?

Solution

What you experience has to do how commands are performed and results especially regarding KVO and such are available after the current runloop finishes. In your case the dot-notation of self.theCollectionView.representedObject = self.representedObject ; hides a KVO call of setRepresentedObject: which automatically gets enclosed in willChangeValueForKey: and didChangeValueForKey: calls. That maybe explains better, why the new representedObject and thus the new view contents isn't available at the moment you run the command but only after the runloop finishes (explanation is more complex!).

Thus with afterDelay: the command is executed after the current runloop finishes and only then the view is filled and top can be reached. This sometimes can be annoying since it seems to break the logical flow. Yet, it is absolutely valid.

OTHER TIPS

You can use GCD:

- (void)updateTheController
{
    [super updateTheController] ;
    self.theCollectionView.representedObject = self.representedObject;
    dispatch_async(dispatch_get_main_queue(), ^(){
        [self.theCollectionView goToTop];
    });
}

[self.theCollectionView goToTop]; will be pushed in queue and performed as soon as posible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top