Adding Pinch/Zoom effect to a UIImageView inside a UIScrollView - iphone

I have a very basic screen sharing iPhone app, I have successfully added the pinch/zoom effect to my app using a UIImageView inside a UIScrollView.
The UIImageView receives the screen content from the PC on a regular interval. Everything works fine but as soon as I scroll/pinch/zoom it works at first but then it stops, and the delegate method that's updating the image view content stops firing up even though the server still sends the screen content. The whole app seems to be frozen but there are no error messages/exceptions/whatever. Can anyone help me, please?

If you are using NSDefaultRunLoopMode, UIAPPlication adds a run loop mode UITrackingRunLoopMode for tracking scrollview events like scrolling. Since the UIApplication switches from NSDefaultRunLoopMode to UITrackingRunLoopMode any events on NSDefaultRunLoopMode will not be called until UIAPPlication switch back to NSDefaultRunLoopMode.
It might be the problem, the fix is change NSDefaultRunLoopMode to NSRunLoopCommonModes .
If you are not sure whether you are using runloop or not as you mentioned in comment. Just search NSDefaultRunLoopMode in your project.

Related

big delay in loading a simple local html (no images) on UIWebView if running at xcode debugger

Right now we are experiencing a weird issue. We have a screen which contains a UIWebView to load a local html content. What I found out that if there could be a big delay (about 20 seconds to 50 seconds) to load up the screen after the methods viewDidLoad and viewDidAppear of that screen are called. This only happens if we load the app into iPhone via xcode debugger and run it at xcode debugger. It won't happen if I run the app directly at the iPhone. If I change the UIWebView to a text view, we won't see this big delay.
Does anyone see similar issue before?
This really puzzles me quite a bit and it would be appreciated if anyone could shed some lights on this.
[Edit]
I add the logging for delegate method of UIWebView, all those call backs are called after those big delays.
2013/08/13 17:05:53|I|907|PolicyViewController|37| entering viewDidLoad
2013/08/13 17:05:53|I|907|PolicyViewController|58| exiting viewDidLoad
2013-08-13 17:06:49.590 [1885:907] Reachability Flag Status: -R -----l- networkStatusForFlags
2013/08/13 17:06:49|I|907|PolicyView|107| entering webView shouldStartLoadWithRequest
2013/08/13 17:06:49|I|907|PolicyView|112| entering webViewDidStartLoad
2013/08/13 17:06:50|I|907|PolicyView|116| entering webViewDidFinishLoad
for the log file, you could clearly see a big delay (nearly 1 minute) between viewDidLoad and UIWebView shouldStartLoadWithRequest method
[Edit-2] Attaching the thread screen shot when I pause the execution during that big delay ( the pause won't happen right away after I press the "Pause" button though)
[Edit-3] we tested the same thing on a iPod touch which should use the same code at iPhone, we didn't reproduce this issue. So at this point it seems specific on iPhone.

Camera turns black upon resume

My app uses multiple features for Apple's demo project AVCam. Everything works just fine except when I exit the app and go back in it, it doesn't show the camera preview anymore. Does anyone know what piece of code I am supposed to use and where it belongs? I tried searching but a lot of questions relating to android popped up.
You need to reinitialize your camera once the App becomes active again. In your app delegate methods, override, applicationDidBecomeActive and send a notification so your view controller knows that your app became active again.
Pending the notification received, you can reload the viewDidLoad, or move the contents of viewDidLoad to viewDidAppear. There's multiple ways to do this. You can also reload the contents of viewDidLoad in viewWillAppear. There's many many many ways to do this, like I said.

How can I make `-[MPMoviePlayerController backgroundView]` to show immediately?

Currently my -[MPMoviePlayerController backgroundView] does not appear until movie loaded enough. So UIActivityIndicatorView which I placed on there does not appear immediately. This drives me crazy. The only solution have been found is placing duplicated indicator-view somewhere between background-view and -[MPMoviePlayerController view]. But this does not look regular, and definitely a view hierarchy hack which is not guaranteed to work properly. If the background-view shows immediately, all will work magically.
How can I make the background-view immediately before movie loaded?
Do not use the backgroundView but the view of the moviecontroller itself...
Following steps (assuming your MPMovieControllerPlayer instance is called moviePlayerController and your UIActivityIndicatorView instance is called activityIndicatorView)
Add your UIActivityIndicatorView on top of the MPMoviePlayerController view (e.g. [moviePlayerController.view addSubview:activityIndixatorView];)
Start animating the activity indicator
Register for MPMoviePlayerLoadStateDidChangeNotification
Within the handler of the above notification, watch out for moviePlayerController.loadState & MPMovieLoadStatePlayable == MPMovieLoadStatePlayable
If the above condition is matched, hide your activity indicator
I am not sure but Can a UIActivityIndicator be displayed over a MPMoviePlayerController in full screen mode? may help you a bit

viewDidAppear not firing ever again after app enters foreground

I have traced a problem in my iPhone app code to the viewDidAppear method not always firing. When you start the app the event fires as expected. However if I close the app using a phone capable of multitasking and reopen in. My viewDidAppear events no longer fire.
My views are loaded from Nibs and I use viewDidUnload to clean up (release and nil all outlets). My views are nested in side and tab bar then navigation controllers. I looks like the events aren't wired up properly when the nibs reload. Any idea on what I'm doing wrong/missing and how I can fix this?
Thanks in advance.
UPDATE I do not mean the event is not fired when the app first comes into the foreground. I mean the event never fires again. Even when changing between tabs or moving though the navigation views.
Example:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"viewDidAppear called");
}
This code is placed in two views, each on different tabs. Each time I swap between tabs "viewDidAppear called" is written to the log. When I close and reopen the app and swap between tabs this no longer happens. Other button events fire normally.
Btw, the viewDidUnload method is really badly named btw -- it's not an 'opposite' to viewDidLoad, it's only called if there was a low memory situation and the view for that controller was unloaded due to not being visible at that time.
(ORIGINAL, NOT SO RELEVANT ANSWER:)
Please see my answer to this similar question:
Why does viewWillAppear not get called when an app comes back from the background?
Basically, viewDidAppear gets called after your UIViewController's view was added to the application's UIWindow heirarchy. Backgrounding then restoring the app doesn't change your view in that respect, so viewDidAppear doesn't get called -- it's correct behaviour, and not a bug. Check out the API docs for UIViewController.
Found it.
While not new to programming I am new to iPhone development. On researching this problem I found it was not recommended to call the viewWillAppear and viewWillDisappear methods manually.
My viewWillDisappear methods resign any keyboards if shown, when my app enters the background it loads a splash screen ready for when the app re-enters the foreground (there is some logic I need to do to work out what the user is shown on restarting the app and I can do this under the splash screen).
As viewWillDisappear is not called when the app goes into the background to make sure no keyboards appeared over my splash screen I was calling viewWillDisapper in the applicationDidEnterBackground method. I guess this also un-registers my events.
By adding viewWillAppear to my applicationDidEnterForeground method my events started firing again. Lesson learned, I will refactor this so I don't call these events manually.
Thanks for the help.

Deferring viewWillAppear until webViewDidFinishLoad

I have an application that uses UIWebViews in several view controllers. The UIWebViews are used to render locally generated html, no slow network access required.
To save memory I only load these on demand as prompted by the viewcontroller viewWillAppear callback. (And unload offscreen instances in response to didReceiveMemoryWarning messages.)
The problem is that the user gets to see the html being rendered, sometimes accompanied by flashes of styling and other assorted unpleasant artifacts. I would much rather the rendering be done offscreen, and reveal the fully rendered view when its ready.
It would be very tidy to be able to have the viewWillAppear not return until the UIWebView is fully rendered. But how?
I tell the UIWebView what to render by sending it a loadHTMLString:baseURL: message. This is asynchronous, and some time (soon) later the webview's delegate gets called back webViewDidFinishLoad.
I experimented with running a runloop inside viewWillAppear, running either the NSDefaultRunLoopMode or UITrackingRunLoopMode. This works in the simulator (it complains to the log
[CATransaction synchronize] called within transaction
but does work) but on a device it deadlocks, with webViewDidFinishLoad never being called.
(Also, it seems like the UIWebView loading property doesn't work. At least, after I call loadHTMLString:baseURL: and before getting the callback it's not true.)
Lots of solutions here I think. A quick one is to load your UIWebView with it's hidden property set to YES. Then set your UIViewController as the UIWebViews delegate and implement:
- (void)webViewDidFinishLoad:(UIWebView *)webView
where you set the property back to NO.
A thing to note is that webViewDidFinishLoad will fire more than once if you have framed/embedded content. So you have to keep track of this. Shouldn't really be a problem if you are loading local content.
I like monowerker's solution best, but another solution would be to hold onto the already-rendered UIWebView all the time (in some more permanent object than the view controller). I'd only do that if the look of monowerker's solution is too disruptive.