Updating UITextView inside UIScrollView while scrolling makes the scrollView stop scrolling - objective-c

I have a scrollView that contains 12 UIViews set as tiles. Each tile contains a textView.
The scrollView has pagination enabled. So, you have 12 tiles per page and you scroll horizontally.
I am updating the textView whenever I receive information from an API call.
This is updating the textView correctly, but I have a huge problem. Whenever the update happens, the scrollView actually scrolls to the view that was just updated. So whenever I load a new column of tiles, the scrollview stops when it begins loading it, even if it has momentum!
Any idea what might be causing this?
If I lazy load the cells without any information in them everything works right, so I'm thinking it has to do with me updating the textView.
I have already tried:
Using an NSTimer (and setting its mode to NSRunLoopCommonModes).
Using an NSOperationQueue and calling the main thread whenever I need to update UI changes.
None of those worked.

i think the solution lies within your post:
"Using an NSOperationQueue and calling the main thread whenever I need to update UI changes."
Whenever scrollView calls for willScroll, stop the current Images being downloaded & when the scroll view stops scroll & its delegate method is called start the new queue to download images.

My suggestion will be debugging it using instrument. In instrument there is a trace template named "Time profiler", you can actually see how much time your application spends on each tasks.
But if you are updating the textViews, of course the main thread will be blocked, so the scroll view stop scrolling until all the textViews are updated. So my suggestion will be tweaking the performance.
Maybe you are loading too much things in each textView?

Related

WatchKit crash due to accepted event even if not everything is loaded

I have made an extension with a storyboard and some table view. In the simulator all is running ok, but when I try the app on Apple Watch I have some troubles. Since the Apple Watch is slower than the simulator it takes about one second to display the table views. During this time in the place of the table view is displayed nothing. If the user press the empty area that will be filled by the table view, as soon as the table view become visible it will be processed the event associated to the table view. I do not know why but this causes the app crash!!! I think everything would be solved if I do like in the other applications on my Apple Watch that while loading the view shows the rotating circle and not the elements of the view that are already in the storyboard (like buttons and labels) added at compile time.
I have to say that maybe the crashed are due to an use of NSTimer that modify some variables modified by the app, maybe I should use a mutex. But I do not figure how in the Apple Watch the application crashes (or it appears the rotating circle and keep rotating) but in the simulator is ALL OK. What can I do? Do you need additional information? Thanks!

How to know that User is still touching the screen in UIScrollView?

I have a scrollView. Typical tableView Cell. I did things a lot on viewDidScroll.
viewDidScroll is called on 2 cases.
User scroll
Sometimes user have stop scrolling but the scrollview still scroll anyway due to momentum, bouncing, etc.
So how do I know if users are still touching the scrollView?
UIScrollView has a BOOL property named tracking that is YES while the scroll view has a touch and NO otherwise. In my testing, it is set to NO as soon as the touch ends, even if the view is decelerating (and still sending scrollViewDidScroll: to its delegate). This seems like exactly what you are asking for.
In my testing, the dragging property doesn't seem to become NO reliably while the view is decelerating after the touch ends.
The decelerating property is also unreliable in my testing. If I touch the scroll view while it is decelerating, decelerating remains YES even though the view has stopped scrolling.
The delegate's scrollViewWillBeginDragging: is called when user starts dragging and scrollViewDidEndDragging:willDecelerate: & scrollViewWillEndDragging:withVelocity:targetContentOffset:(iOS 5+ without paging enabled) is called when user lefts his/her fingers.
You may also want to check scrollViewWillBeginDecelerating: and scrollViewDidEndDecelerating:.
Ref: http://developer.apple.com/library/ios/#documentation/uikit/reference/uiscrollviewdelegate_protocol/Reference/UIScrollViewDelegate.html

Can I maintain smooth scrolling when loading HTML into child UIWebView?

I need to show a paginated slideshow of moderately DOM-intensive HTML pages in an iPad application.
All documents are tailored for iPad screen so there is never any scrolling inside UIWebViews.
I decided to put UIWebViews inside UIScrollView for pagination.
It works really well and smooth after all web views have rendered their content.
However, I can't afford waiting for 20, 30 or 50 web views to load before user can scroll: it takes minutes.
I tried to anticipate swipes in scrollViewDidScroll handler and pre-load a few next pages as user keep scrolling.
This worked much better (no performance difference between 10 or 150 web views).
However calling loadHTMLString in scrollViewDidScroll handler causes scrolling to lose it smoothness.
I don't care if it takes a second longer to show a particular UIWebView—all I want is for scrolling to be smooth and available as soon as possible, and to lazily preload UIWebViews on the go.
How do I achieve that?
This is a difficult problem and there is no easy/elegant way to solve it.
One way to speed up the scroll would be to lazy load the pages as you stated in your question. However, in order to ensure smoothness you would have to control when the loading happens.
So say you began by loading the first 5 pages on initial launch. When the user scrolls to page 2 and STOPS, you begin loading page 6. As soon as the user starts scrolling again you pause the loading only to resume when they have stopped on a new page. Pausing the loading in between will help smooth out the scrolling. Also, make sure you release data when possible because it can build up and hinder smooth scrolling down the line.
Another option would be to have the UIWebViews begin loading only as soon as the user stops on the page. So say I scroll to page to, once the scrolling stops I begin to load the HTML. This is not as "pretty" as the first options but it will ensure that the scrolling is smooth.
Another option, this one is a bit out there, is to run through and load all the HTML pages rich text. Leaving out all the DOM intensive stuff. Then grab a screen shot of those semi-loaded page using this method. When the user stops on the page you load it all the way including the DOM intensive stuff. This will let the user feel as thought they are scrolling quick with everything loaded.
Here is a great scrolling class that I have used before.
Here is some code to help with method 3.
Good luck and I hope that this helps!
EDIT:
Here is a great post from the guys at LinkedIn on how they solved webView scrolling problems. It would be worth a read.

Reverse animation before it is finished

I have a button and when the user touches down and holds a popup appears. However, when the user releases his thumb before the pop animation finishes I'd like the animation to stop where it is and autoreverse to the initial position. How can I accomplish this?
Currently I'm simply using UIViews -animateWithDuration:animations:completion:. Do I have to set the animations explicitly in this case?
I've already tried reading the current state from the presentationLayer properties, but that somehow didn't work.
You can start the second animation using the UIViewAnimationOptionBeginFromCurrentState option. This will stop the first animation if it's still running.

How can I differ between manual and automatic scrolling in NSScrollView/NSTextView

I subclassed NSTextView and added support for automatic scrolling in a userdefineable time.
Now I want to detect, if the user manually scrolls, while the view is scrolling automatically.
Then I want to immediately stop automatic scrolling, until the user stops his action and then I want to start scrolling again from the new position.
I want to do this in such a matter, that the user can move around without a stuttering view.
I use boundsDidChangeNotification to calculate the scrolling position (playtime) and show it in a label, but I can't use it to detect the user manual scrolling, because it is also pushed by the automatic scrolling...
Would be very nice, if anyone has an idea ;-)
Thanks in advance
Gerald