UIScroll animation is interrupted by NSFetchedResultsControllerDelegate processing - ios

When the keyboardWillHide, I scroll the tableView to a specified point. The code is below. This works well.
Now, I implement NSFetchedResultsControllerDelegate. I set it "on" by setting fetchedResultsController.delegate = self; The scroll animation is interrupted. The NSFetchedResultsControllerDelegate is calling [tableView beginUpdates], which I think is causing the interruption on the tableView animation.
How can I prevent the scroll animation from being interrupted and still implement NSFetchedResultsControllerDelegate?
- (void)keyboardWillHide:(NSNotification *)notification {
[screen setHidden:YES];
[suggestView setHidden:YES];
[_tableView setContentOffset:origin animated:YES];
}

I found out that you can't do animations in keyboardWillHide. You shouldn't do any animation in any "WILL" event.

Related

Removing an observer from an UIView

I have an observer on an UIView to adjust a UIWebView when the size is changed (e.g. on rotation of the device):
[[self view] addObserver:self forKeyPath:#"frame" options:0 context:nil];
Naturally I need to remove this observer when the view is dismissed (otherwise there is an exception). But where would I do this? I tried in dealloc, or in viewDidDisappear, but I get a SIGABRT when I do this.
- (void) viewDidDisappear:(BOOL)animated {
NSLog(#"Is moving %d - %d", self.isMovingFromParentViewController, self.isBeingDismissed);
[[self view] removeObserver:self forKeyPath:#"frame"];
}
I tried to move it in earlier on ViewWillDisappear, but the same result.
Moreover, I am not completely happy with this later solution (even if it would work), as it will potentially also unload when the view is temporary out of view (i.e. with pageViewController), although that is not that big a deal for me at the moment.
Tracking the problem down to this item and trying to solve it has already cost me a day, so any suggestions are really appreciated!

UIPageViewController didFinishAnimating not called if swiped quickly

I have a UIPageViewController that works as expected. I can scroll left and right and the delegate method didFinishAnimating is called when I scroll each direction. However, if I scroll too quickly I end up on a page where didFinishAnimating is not called, though it is called for all previous pages. Does anyone know why this might be happening?
I would think that didFinishAnimating would be called on every page transition regardless (e.g., even if the turn was aborted).
This bug is still here in 2017.. I tried many alternative ways.. now I gave up the hope that this will be fixed by Apple and I think the best way is to use protocol to bound UIPageViewController with content ViewController, so we can notify UIPageViewController in viewDidAppear()
I've got the same issue. I tried to use the UIScrollView delegate instead of UIPageViewController to solve the issue. This is a tricky method, not recommend to use.
1.get the UIScrollView in UIPageViewController to set delegate:
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView *scroll = (UIScrollView *) view;
scroll.delegate = self;
}
}
2.override scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[[NSNotificationCenter defaultCenter] postNotificationName:PageSwitchingBegan
object:nil];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
[[NSNotificationCenter defaultCenter] postNotificationName:PageSwitchingEnded
object:nil];
}
You may also try override - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView instead of scrollViewDidEndDragging to achieve better result.

Pause any operations while UIScrollView is scrolling

I have a big paginated UIScrollView with severals image and views in it. The thing I'm trying to achieve is to pause any background operation while the user is swiping through pages. I need this because the app is downloading and computing stuff and the swipe animations isn't smooth.
Any ideas?
Thanks
You should think in reverse manner.
Once the image was downloaded in background then update it in UI by using Main thread.
The Main Thread is handling the UI updates.
Based on your description,
"the swipe animations isn't smooth"
You are downloading images on Main thread.
You can use NSOperationQueue and catch the scroll event in the UIScrollView's delegate to pause/continue the operations.
- (void)viewDidLoad{
[super viewDidLoad];
queue=[[NSOperationQueue alloc]init];
NSBlockOperation *intenseOperation=[NSBlockOperation blockOperationWithBlock:^{
//do intense stuff
}];
[queue addOperation:intenseOperation];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[queue setSuspended:NO];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[queue setSuspended:YES];
}

Finish up existing iOS animation

I have an application with multiple views that transitions to the main screen depending on which button was pressed. My current problem is that if the view is in the middle of animating then when the user selects another button then the whole layout becomes messed up. (ex: the views don't align with the screen meaning that they become a few pixels off)
What I would like to know is if there is a way to check if the view is currently animating and if so just have it animate to the last frame and skip anything in between. Below is a small piece of code that I have just tested based on what I have read on other user asked questions on SO:
-(IBAction)buttonPress:(id)sender
{
if([selectedView.layer.animationKeys count] > 0)
{
[selectedView.layer removeAllAnimations];
}
// Perform other calculations once the animation has stopped
}
There are many ways to do this but....
If you are using block animations you could set a "isAnimating" flag when the animation starts and set it again in the completion block. You could check the bool from anywhere and handle cases as needed.
As for needing code to execute after an animation occurs, but
// animation code in some method...
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
isAnimating = YES;
fooView.alpha = 0.0;
}
completion:^(BOOL finished){
isAnimating = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:#"FooBeDone" object:nil userInfo:nil]
}];
-(IBAction)buttonPress:(id)sender {
if (isAnimating) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doBar:)
name:#"FooBeDone"
object:nil];
// possibly disable button to prevent multiple taps?
} else {
[self doBar];
}
}
- (void)doBar {
// do what needs to be done when when the animation is over
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"FooBeDone" object:nil];
// possibly enable button again
}
edit: I added more code to show a possible notification method. Creating extended loops in your IBAction will lock the user interface until the loop finishes and you can get back to the main run loop, so it's highly advised to avoid it. Notifications should give you the same effect but allow your main run loop to continue unhindered.

[tableView reloadData]; doesn't work until I scroll the tableView

I have a simple app that downloads search results in XML when the user types in a UISearchBar. The download+parsing is threaded and once done it fires an NSNotification to tell the ViewController with the table view to [tableView reloadData];
Here is the code that receives the notification fired once results are in:
- (void)receivedResults:(id)notification {
results = [notification object];
DLog(#"Received %i results",[results count]);
[[self tableView] reloadData];
}
I get the log output "Received 4 results", but the table view doesn't reload the data until I scroll/drag it a couple pixels. I am using the built-in UITableViewCellStyleSubtitle cell style and im not changing the height or ding anything fancy with the table view.
What am I doing wrong?
I was able to get the same thing to work. But the issue was that the reload data needed to be called on main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
I think this is more practical than the performSelectorOnMainThread option
Call
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
instead of
[self.tableview reloadData]
My problem was that I was posting a NSNotification from a background thread. To avoid this, simply wrap your postNotificationMethod in a dispatch_async method like this:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"FinishedDownloading" object:result];
});
When this notification will be received, the tableView.reloadData will be called on the main thread.
I have the same problem, and I have tried all the solution I can find on google. But All of them don't work.
At last I found that I add observer before viewDidLoad, and then [self.tableView reloadData] is not working.
First I call the setObserverForUserInfoDatabase in the viewDidLoad of my root navigation view controller. Because I think it was called earlier. The function is like this:
- (void)setObserverForUserInfoDatabase:(NSString *)name {
[[NSNotificationCenter defaultCenter] addObserverForName:name
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
[self loadUserInfo];
[self.tableView reloadData];
NSLog(#"User Panel Notification \n %#", self);
}];}
Then I move the code into viewDidLoad of the viewController itself.
- (void)viewDidLoad {
NSLog(#"View Did Load");
[super viewDidLoad];
[self setObserverForUserInfoDatabase:UserInfoDataBaseAvailabilityNotification];
}
And then everything works fine.
I don't know the reason yet. If anyone knows please tell me.
reload your tableView in viewWillLayoutSubviews

Resources