UITableView not scrolling after switching to iOS 7 - iphone

In iOS 6, I had a UITableView created using QuickDialog in my app. It scrolled normally. When I switched to iOS 7, the same UITableView does not scroll properly. I can drag to the bottom (the scroller compresses) but when I release, it pops back up the to the top. I've been playing with viewDidAppear to try and diagnose the problem. See the code block below.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"Content height: %f",self.quickDialogTableView.contentSize.height);
[self.quickDialogTableView reloadData];
NSLog(#"Content height: %f",self.quickDialogTableView.contentSize.height);
[self.quickDialogTableView layoutIfNeeded];
NSLog(#"Content height: %f",self.quickDialogTableView.contentSize.height);
}
The output of this block in iOS 7 is
Content height: 0.000000
Content height: 836.000000
Content height: 0.000000
Meanwhile, the output of this block in iOS 6 (simulator) is
Content height: 836.000000
Content height: 836.000000
Content height: 836.000000
Also to try and diagnose the problem, I set up a button that would trigger [self.quickDialogTableView reloadData]. Whenever that button is pushed, the scrolling behavior begins to function normally. Then when I leave the view and come back, the scrolling fails again (until the button is pushed). To be clear, I have tried to put a reloadData in viewWillAppear by itself (i.e., removing the last two lines in the code block above) and it does not correct the scrolling.
I'm looking for clues as to where I might look to correct the issue. Thanks in advance for any help.

Okay, so I couldn't figure out the source of the problem but I did find a workaround that I hope helps someone else. Or at least, maybe helps someone else point out what's really wrong.
I created a property called trueContentSize where I store what the correct size is.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.quickDialogTableView reloadData]; // Calculates correct contentSize
self.trueContentSize = self.quickDialogTableView.contentSize;
}
Then, in -viewDidLayoutSubviews I correct the contentSize manually.
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.quickDialogTableView.contentSize = self.trueContentSize;
}

Just thought I might throw in my two cents here..
Same problem was happening to me. Table loads fine at first, but navigate to a different screen, come back, and the table view's contentSize is 0,0 and unscrollable. Fausto's workaround wasn't reliably working, either.
What turned out to be the case for me was just the act of referencing topLayoutGuide in -viewWillLayoutSubviews. Doing that causes all of the above symptoms. Try it out in a new project:
Setup a table view controller inside a tab controller.
Give it 30 rows with just static content.
Run and you can scroll. Switch tabs, then back, and you can scroll.
Add NSLog(#"%#", self.topLayoutGuide); in -viewWillLayoutSubviews
Run again, you can scroll, but switch tabs, no more scrolling.
Weird. Sounds like an iOS bug, or you just shouldn't reference topLayoutGuide in that method. Removing any reference to that property will fix the issue.
Edit: As of earlier this year, Apple confirmed via a Radar report I made this is an iOS bug. Don't reference topLayoutGuide until it's been resolved (whenever that will be, heh). :)

This is my current temporary fix. Anyone figure out the real fix?
#interface UITableView (Extension)
#end
#implementation UITableView (Extension)
- (void)setContentSize:(CGSize)contentSize {
if (contentSize.height != 0) {
[super setContentSize:contentSize];
NSLog(#"set content height %f", contentSize.height);
} else {
NSLog(#"set content size zero");
}
}
#end

Faced the same problem and the only solution found was to reload the data in the table. Hope that helps.

I had a similar issue. My issue was that I had an explicit height set for the table view in the storyboard. Updating my table view to make use auto layout by setting distance to the views above / below made it work for me.

Related

Assertion failure in UIQueuingScrollView didScrollWithAnimation:force:

I've got a UIPageViewController set up paging my ImageViewController.
The ImageViewController contains a UIScrollView with a UIImageView inside. Nothing else.
I'm testing at the moment with 3 "items" in my datasource for the UIPageViewController (i.e. three pages).
It all works fine and I can scroll and zoom and then page for about 30 seconds and then suddenly I get this warning...
*** Assertion failure in -[_UIQueuingScrollView _didScrollWithAnimation:force:], /SourceCache/UIKit/UIKit-2372/_UIQueuingScrollView.m:778
I've got no idea where to start debugging it though as it doesn't point to any of my code and there isn't any of my code in the stack or anything.
Can someone give me a pointer as to where to start debugging this.
EDIT
I've done a bit more testing. It seems to happen if the scrollView is decelerating (i.e. after a flick) and then I try to transition the PageViewController to another ViewController as the scrollview is still moving.
The app crashes about 20% of the way through the transition to the next page.
EDIT 2
The error seems to stop on the line _cache_getImp (not sure if that's a capital i or lowercase L).
EDIT 3
This gets better. I just downloaded Apple's PhotoScroller sample app to see if they got round the problem a different way. Well, no, they didn't. The sample app crashes in exactly the same way mine does! You have to zoom and scroll and transition pages at the same time to make it more likely to crash but it happens on it's own too it just might take longer to happen.
Came up with a solution! In my case I have a UIPageViewController with UIPageViewControllerTransitionStyleScroll as well as next buttons that allow the user to advance through my viewpager by tapping. I am getting this crash when the user presses a next button and drags around slightly before releasing their finger (still within the frame of the button). It appears that the dragging within the button is interfering with UIPageViewController's pan gesture recognizer in this case, and that's what causes the crash.
While it's pretty unlikely that the user will get in this state, I've come up with a relatively simple solution the prevents my app from crashing if it does happen. I have a boolean that represents if the user is in a valid state to move to the next screen and set it to YES on touch down, then to NO if the user drags anywhere inside my button. Then, on touchUp (nextPressed) I check the boolean before moving my UIPageViewController programatically.
- (IBAction)touchDown:(id)sender
{
self.shouldAdvanceToNextScreen = YES;
}
- (IBAction)touchDragInside:(id)sender
{
self.shouldAdvanceToNextScreen = NO;
}
- (IBAction)nextPressed:(id)sender
{
if (self.shouldAdvanceToNextScreen) {
UIViewController *initialViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"TutorialScreen2"];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}
}
The downside is that nothing will happen even though the user still released their finger within the button frame. However, I prefer this over a crash and see this as a pretty rare edge case regardless. I'd expect the user would just tap again - this time without a tap & drag - and move forward successfully.
I'd welcome any ideas on taking this a step further and preventing the clash between the touch drag and the UIPageViewController altogether.
Have you tried disabling bouncing in the UIScrollView? That worked for me and solved my other problem too alluded to in my comment above.
I have been fighting with this all day.
My Conclusions:
If you have a scrollview as the showing ViewController and you are delegate of the scrolls: you're in trouble. Even with the PageViewController configured with Horizontal scrolling, a vertical scrolling on your view will trigger an event. -> this does not cause trouble if: you scroll back to the top of your view before (Not sure how to fix this).
There are good StackOverflow threads like this one.
Basically the solution is:
1 [yourView setViewControllers:yourControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
2 Use UIPageViewControllerTransitionStylePageCurl as the transition Style.
This fixed most of my problems.
If someone has a solution for the delegation problems with the scrolling, will be most wellcome
I had a similar problem. My setup was a UIPageViewController and I was loading view controllers with an UIImageView inside. When interacting while the UIPageViewController was scrolling I got the same crash log.
I fixed it by creating a UILongPressGestureRecognizer and add to the UIPageViewController's scroll view.
Created my own subclass of UIPageViewController (Solution is specific for my case but can easily used as a generic solution)
Find the inner UIScrollView of the UIPageViewController
- (UIScrollView *)findScrollView
{
UIScrollView *scrollView;
for (id subview in self.view.subviews)
{
if ([subview isKindOfClass:UIScrollView.class])
{
scrollView = subview;
break;
}
}
return scrollView;
}
Add the long tap gesture recognizer to the inner scroll view and point its action to a method or nil
/**
* On tap-hold the page view controller crashes as soon as it pages to a new view controller.
* Setting a long press gesture to ignore the hold.
*/
- (void)listenForLongPressGestureOnScrollView:(UIScrollView *)scrollView
{
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:nil];
[longPressGestureRecognizer setMinimumPressDuration:0.5];
[scrollView addGestureRecognizer:longPressGestureRecognizer];
}
It surely looks like a bug in iOS 8 and 9.
(and the "answers" down below attempt to work around that)
Feel free to file a ticket on bugreport.apple.com
Do be sure to specify how to crash PhotoScroller
Include all iOS versions you've seen it crash on
To date I've seen:
Assertion failure in -[XXX.TrackingPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UIPageViewController.m:2028
Assertion failure in -[_UIQueuingScrollView _didScrollWithAnimation:force:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/_UIQueuingScrollView.m:785
(lldb)
I'll keep the list updated (Despite the downvoting, however massive).
Stay tuned.
It does not look like our bug.
UPD 2016 09 27 (on Xcode 8 now):
Assertion failure in -[XXX.TrackingPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit/UIKit-3347.44.2.2/UIPageViewController.m:1875
awesome

UIBarButtonItem - Invalid tap glow size

I have a strange problem with glow that appears when pressing on a UIBarButtonItem in the UIToolbar control. When I set ImageInsets property to 4,0,0,0 the glow gets smaller every time I tap on it. Here is an illustration:
The problem doesn't appear if I don't set imageInsets. The problem appears for all buttons in the UIToolbar. I don't have tap handlers. Making bigger inset (e.g. 8,0,0,0) produces the same result faster.
I appreciate any suggestions on how to solve the problem.
EDIT: Changed the code to Objective-C since the problem reproduces without MonoTouch as well.
It's default single view project. I added a toolbar and a UIBarButtonItem into it using storyboard designer. Created an outlet for the button.
#import "ViewController.h"
#implementation ViewController
#synthesize testBtn;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 0, 0, 0);
[testBtn setImageInsets:insets];
}
- (void)viewDidUnload
{
[self setTestBtn:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
It is hard to see what the problem is without code. Would you mind posting the relevant parts of your code up? I am thinking it has something to do with you repeatedly incrementing the top inset by 4... I will edit my answer once I see the relevant code.
EDIT: So I am not familiar with Monotouch... and from the code you pasted I am assuming the constructor does indeed get called once. I am thinking there may be a bug in the Monotouch framework which is causing the imageinsets to be shifted by the specified amount (down 4) every time the button is tapped. I would check in the following order:
That the delegate method tied to the button is not pointing to the constructor.
Change the inset to (8,0,0,0) and in 5 taps do you see the same image as above (10x). If so it may be an issue with the monotouch framework or with how you hooked up your delegate method.
Sorry but I am unfamiliar with monotouch so I can't provide much more assistance. Unless you are locked into using Monotouch, I would strongly recommend you learn native Objective-C and program natively to avoid small pitfalls and headaches such as this. Objective-C and the iOS SDK is pretty elegant.
Finally, I asked designer to adjust image size and thus get rid of the imageSize property use.

iOS 5 issues: Navigation bar clipped after dismissing modal

I have a nice little app on the app store that does pretty well for itself. Life was great until iOS 5 came to town. Now, I have a number of issues with my app that I have no way of fixing because I have no clue what is going on, because I feel that they are iOS 5 issues, not mine.
Was there an iOS 5 conversion manual I missed? Or did they just change everything for fun, and want us to figure out where all the easter eggs were?
Here is another issue I am experiencing (that I have wasted so much time trying to fix), that DON'T EXIST AT ALL when I simply say that I want to run the app in good ol' 4.2:
Modal view
My app is a simple reader app. I have a book reading view that displays text with a UIWebView. One of the features I have been working on involves the ability to take notes as you read. This is achieved by hitting a button, and presenting a modal view. Yes, a modal view. The most simple pre- iOS 5 thing you could possibly do. Now, when I dismiss my modal view, just by hitting cancel, and simply dismiss the view, when I get back to my reader view, the navigation bar at the top is pushed up half way off the screen! This doesn't happen in 4.2, but there it is in iOS 5!
What can I do to get this issue resolved?
Thanks for your help.
Ok, I was just able to figure out what in the blazes was going on. I had the shouldAutorotateToInterfaceOrientation value set to a BOOL variable, so that when the modalView was coming back, it didn't know the state/size of the status bar. Fixed that, and the problem disappeared.
I have the feeling it has something to do with the way you present and dismissing the modalview. Apple introduced a new method to present views. May you try using theses instead of the old ones and see if it fixes your problem.
So here is what you do:
change this method:
presentModalViewController:animated:
into the new preferred method introduced with iOS 5:
presentViewController:animated:completion:
Depending if you are using dismissModalViewControllerAnimated:to dismiss your view, change it into dismissViewControllerAnimated:completion.
This methods also have completion handler which is very useful to do some extra work after the view has been presented/dismissed. Maybe that also helps with your other issue. Let me know if that might helped.
A major change in iOS 5 is that the navigationController property of UIViewController is no longer set for modal views. Instead, there is a new (not present in iOS 4) parentViewController property. So where you're using navigationController in a modal view you need to change the logic to something like:
UIViewController* parent;
if ([self respondsToSelector:#selector(parentViewController)]) {
parent = self.parentViewController;
}
else {
parent = self.navigationController;
}
(That's from memory, so I can't guarantee that every t is dotted and every i crossed.)
I was seeing this same clipping problem.
I found out that the reason for my issue was that I set the content size within the modal dialog (something I did for my iPad layout), so removing these two lines seemed to fix the issue:
CGSize size = CGSizeMake(320, 480);
self.contentSizeForViewInPopover = size;
I thought the problem was fixed but it wasn't. After reviewing the code some more, cleaning the build, and retesting it turned out to be a shouldAutorotateToInterfaceOrientation which would return NO for all orientations, for a brief amount of time (flag == NO) while the app is loading (root controller). You want to at least return YES to one orientation like so:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return !self.flag ? UIInterfaceOrientationPortrait == toInterfaceOrientation : YES;
}

UIScrollView works as expected but scrollRectToVisible: does nothing

I have used UIScrollView before, and am using it now, and never had a problem. I'm now adding it to an old app, and while it works as expected (I can look at the contents, scroll around with my finger, all the bounds and sizes are setup right so there is no empty space in the content, etc.), I just can't get scrollToRectVisible to work. I have even simplified the call so that it merely moves to the 0,0 position:
[scrollView scrollRectToVisible:CGRectMake(0, 0, 10, 10) animated:YES];
or move it to 0,200:
[scrollView scrollRectToVisible:CGRectMake(0, 200, 10, 10) animated:YES];
I even made a quick app to test this and I can get scrollRectToVisible to work there as I expect. But in my old app, I can't seem to make it do anything.
I can make the scrollView scroll with setContentOffset:, but that's not what I want.
This scrollView and its contents are defined in the nib by IB and used with an IBOutlet. The only code I am using in my app to handle the scrollView is
[scrollView setContentSize:CGSizeMake(scrollView.contentSize.width, imageView.frame.size.height)];
(I'm only interested in vertical scrolling not horizontal).
Has anyone run into a problem like this?
I have compared the scrollView attributes in both apps and they are identical.
ADDENDUM:
My scrollViews frame is: 0.000000 0.000000 480.000000 179.000000
My scrollViews contentSize is: 0.000000 324.000000
It still acts like the rect I want to scroll to is already visible and no scrolling is needed. Not sure if that is what is happening. This is just the darnest thing. Seems like such an easy thing to resolve...
ADDENDUM #2:
This is how I am making do without scrollRectToVisible:
CGPoint point = myRect.origin;
if (![clefScrollView pointInside:point withEvent:nil]) {
point.x = 0;
if (point.y > clefScrollView.contentSize.height - clefScrollView.bounds.size.height)
point.y = clefScrollView.contentSize.height - clefScrollView.bounds.size.height;
[clefScrollView setContentOffset:point animated: YES];
}
Everything else about this scrollView works as expected, but scrollRectToVisible. WHY?!? Any wild guesses?
Over a month later, and I finally figured it out. While the alternative above worked well, it has been bugging me and I had to finally figure it out. Turns out that it was somewhat of a stupid mistake.
Here's the old code in my viewDidLoad, where I set up the scrollView:
[clefScrollView setContentSize:CGSizeMake(clefScrollView.contentSize.width, clefView.frame.size.height)];
The value of a scrollView height or width can't be 0! I think this got past me because I was assuming that ScrollView sizes start out with a valid size, and I was missing the fact that one dimension was zero!
This works:
[clefScrollView setContentSize:CGSizeMake(clefView.frame.size.width, clefView.frame.size.height)];
Yeah, I have not had success with scrollRectToVisible:animated:, but setContentOffset:animated: always works for me. Out of curiosity, why do you not want to use setContentOffset:animated:? It seems to be the proper solution.
You might want to check and see that the scrollView's delaysContentTouches property is set to NO.
If you call the method scrollRectToVisible or setContentOffset from a touch within a subview of your scrollView then your scrollView could be holding things up by delaying touches.
So, make sure you set the following in your scrollView.
scrollView.delaysContentTouches = NO;
You will most likely be able to move the scrollView with and without animation set to YES.
i had it like this and it didn't work
scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, someKnownValue);
i was just changing the height of the contentSize, so I didn't think that would give me any problem but it did ...
had to change it to this
scrollView.contentSize = CGSizeMake(someOtherKnownValue, someKnownValue);
turns out scrollView.contentSize.width is not necessarily set to a valid value from the get go, so better give it an specific value
The suggested solution above may still give an error if you haven't set the frame for the "clefScrollView".
If the solution above is used and still having the same problem, make sure you have initialized your scollView (in this case clefScrollView) frame prior to setting the content view.
clefScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,320,450)];
[clefScrollView setContentSize:CGSizeMake(clefView.frame.size.width, clefView.frame.size.height)];
A little late to the game but I was having the same problem. Though I absolutely had my scrollview's content size set correctly - even excessively so for the height value. Even after extensive checks to validate the frames and content sizes - still wasn't working. I had to adjust the "bounds" frame height, then everything worked great.
I had the same symptoms as this issue..the scrollRectToVisible was not working as intended. My problem was that the scrollview on the storyboard had a ambiguous constraint problem. Once that was fixed the call worked just fine. It is something else to check when the scrollRectToVisible call isn't working as intended.
For me the problem was that a constraint in a subview was not explicit.
Check that every constraint in your content is set, even if you are not needing it apparently for the layout.

scrollsToTop doesn't work when UIWebView used with pushViewController, looking for solution

I have an app with a table view at the root in a navigation controller, and on selection of a table cell it displays a new view controller that contains only a UIWebView (with a toolbar and a navbar).
Depending on how I present the new web view, the feature where the user can tap on the status bar at the top and have the webview scroll to the top, either works or doesn't work.
If I use:
(void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
on the RootView, then the webview does scroll to the top.
If I change that one line of code and instead use:
(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
on the navigation controller, then the scrollsToTop feature stops working.
What I really want to use however, for other reasons in the context of the app, is the pushViewController method. BUT, I also want to keep the scrollsToTop behaviour.
I have so far tried various approaches, some described here:
-Attempting to set the webview internal scrollView scrollsToTop property
((UIScrollView *)[[webView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = YES;
(No discernible effect).
-Changing the ordering of setting NavBar properties or not setting any at all
-Adding extra "window makeKeyAndOrderFront" calls after the new view push.
I don't believe there are other views there that could be claiming the "scrollsToTop" property (and the first test above proves that in any case).
Short of attempting to embed UIWebView into a UIScrollView, which I expect will be painful, I have run out of routes to explore to resolve this issue.
I am hoping someone else has found a way to correct this?
Try the reverse approach as a workaround.
In the root view controller:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.tableView.scrollsToTop = NO;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.tableView.scrollsToTop = YES;
}
Bye!
It turns out that it wasn't working because of the way I was customiing the Navbar. I was overriding leftBarButtonItem with a UIBarButtonItem that then took up the whole navbar (I think I took that approach from some Apple code many months ago, but not sure). I was using the same approach on another view and the scrollsToTop worked fine there.
Taking that code out and putting the custom Navbar view into (eg)self.navigationController.titleView instead solved this problem. I do not really know why, like I say it works fine for other views.
I wasted a lot of time with this problem, so I hope I save someone else some hair by describing it here :)