I am using the example from TheElements sample code provided with the iPhone SDK to achieve flip transition between 2 views. The transition from the 1st view to the second is not as responsive as the one from second to first. I am not sure why this is happening. The transition does happen but takes almost double the time it should.
I tired comparing my code with the one in TheElements and don't see much difference in the transition portion. Any ideas?
Thanks.
It could be any number of things, but I suggest you start with your viewWillAppear: and viewDidAppear: methods as well as viewWillDisappear: and viewDidDisappear:.
You're most likely doing something rather processor intensive that's causing the slowdown.
Related
I'll try to keep this short.
I was using viewDidLayoutSubviews to (mostly) apply corner radius to some views in several UIViewControllers.
Also doing the same in layoutSubviews for custom UIViews.
After installing Xcode 8 Beta, this stopped behaving predictably.
Some times it works, others works with a delay, others still, not at all...
The one thing that was immediate while debugging was that on first call of viewDidLayoutSubviews, bounds are zero for the views in question.
On second call, the bounds are correct; the thing is, as I said, the second call either has a (visible) delay, or never happens at all.
Any pointers?
Thank you all in advance.
Best,
Renato.
Answering my own question, just in case someone bumps into the same issue...
As far as I can tell, in iOS 10 you cannot assume calls performed on layoutSubviews, viewDidLayoutSubviews, etc. will be called on the main thread.
So the answer seems to be simply wrapping the UI calls on a dispatch block (new iOS 10 sintax):
DispatchQueue.main.async {
// Do UI stuff here...
}
Hope it is helpful for someone :)
Best regards,
Renato.
I've got a view controller whose view contains a UIImageView that does animation:
//AnimationViewController::ViewDidLoad event:
var ctlAnimations = new UIImageView();
ctlAnimations.AnimationImages = list.ToArray(); //<--list contains the UIImages
ctlAnimations.AnimationDuration = 1.0 * list.Count;
ctlAnimations.StartAnimating();
this.Add(ctlAnimations);
This works perfectly: when I push AnimationViewController onto the navigation stack, it displays and animates the UIImage.
But now I need to show AnimationViewController with a custom animated transition:
var transition = CATransition.CreateAnimation ();
transition.Duration = 0.3f;
transition.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);
transition.Type = CATransition.TransitionFade;
this.View.Layer.AddAnimation (transition, "fade");
//viewController is being pushed with animated=false, because we have a custom animation
base.PushViewController (viewController, false);
this.View.Layer.RemoveAnimation("fade");
This also works perfectly, in that the new View transitions into place using the specified custom animation.
But when I push AnimationViewController onto the stack using an animated transition, it displays but the animation doesn't run. Instead, it shows the first frame of the animation (the first image in the list), and doesn't run it.
So, something about the transition is breaking the ability to animate a UIImage in the new view controller, but I simply can't figure out what to do about it.
Update: I've noticed that if I tap the NavigationController's back button, but then move off of the back button and let go (so I don't actually go back), the animation starts playing!
PushViewController works like this: Over the current view controller the next view controller is placed you can say pushed onto the stack. From Apple docs its clear that either you need to push view controllers either with animation or without.
Work around:
Set the frame of the next view controller's view's x position beyond
the screen's right
Suppose width of the screen is 320, then set the x position of next
view as 320.
Add the next view as subview to the existing one.
Now do your custom animation.
Another work around:(a bit more overhead though)
Take a snapshot programmatically of current view.
Add the snapshot image as the initial view of next view controller.
Now push view controller without animation. (User will still see the old view)
In viewDidAppear of new view controller start your custom animation.
[I have to warn you that this method of taking snapshot might give you a small delay in older devices. Newer devices are pretty fast enough you wont see any lag]
Let me know if any issues in case you are implementing any of these solutions.
Try putting the animating bit in ViewDidAppear rather than ViewDidLoad. Also, try using breakpoints and NSLogs to follow what happens after the animation, starting with the ViewDidLoad and ViewDidAppear. Try having the animation repeat forever so you can see if it has ever been animating or not.
I'm very curious what the culprit is here as well. Why is the animation not displaying correctly in some cases?
My theory is that you have placed animation code in viewWillAppear rather than viewDidAppear. Animation code does not run properly when placed in WILL or SHOULD methods.
Can you please post back what caused the issue?
Suspicion #1
I am betting that your code is not being called because it is in ViewDidLoad. I believe you are creating a customized view stack, that means you need to be using the ChildViewController methods from Cocoa.
I am unfamiliar with MonoTouch (I only write pure CocoaTouch), so this might not be 100% correct
I would be consoling out your viewDidLoad and viewDidAppear methods and absolutely make sure they are being called. It is my suspicion that viewDidLoad IS NOT. And this is causing viewDidLoad to not be called on the UIImageView.
In your code you probably need the equivalent of (from objective-c):
[self addChildViewController:viewController];
// OR?
[base addChildViewController:viewController];
This tells the 'parent' viewController that the Child has been made visible, so call the viewDidLoad/Appear and Unload/Disappear methods when appropriate. This might not exist in MonoTouch, or the Push methods might not be fully implemented, so you might need to do some hacky (bad) stuff like manually calling the viewDidLoad method manually.
Suspicion #2
It could also be that your 'list' variable (the one holding the images) is nil. If that happened the animation would not run. OR maybe it has something to do with the duration of your animation, try to set it to whatever would make it repeat forever. Be sure it isn't running REAL FAST somehow and you are just missing it.
begin philosophical musing
Either that or start learning actual Cocoa development :) Not meant as a flame, but definitely meant seriously, you are going to run into problems trying to develop applications through translation layers (custom language-bridges meant to get around writing the base language of a framework/application/platform).
Titanium/MonoTouch/PhoneGap will never produce as robust or high-quality applications as real Objective-C. And besides that, once you learn Cocoa it will change how you write everything else, and I doubt you will want to go back. As the wonderful website of the same name says, 'Cocoa is my girlfriend'
Let me tell the something about UI in IOS. In IOS access to the UI Elements is limited to a single thread.
The single thread would always be the mainThread except in the case when you are running an animation.
Hence when u are performing number of animation at the same instance you have to use
beginAnimation.
setFrame (or) some methods that changes state of UI element.
Repeat step2 for all those objects u are scheduling to animate.
comitAnimations to perform all animations at once. (using comit animations ensure all the animations are performed on same thread)
So, I guess here is what happening in ur case.
Viewcontroller started an animation to push the view controller into stack.
Image view started another animation before finishing first animation.
Look at the links to get a clear idea link1 and link2.
Well Let's get into the solution
Add an ivar and retained property named ctlAnimations to your class
In ViewDidLoad (or) ViewDidAppear
self.ctlAnimations = new UIImageView();
ctlAnimations.image=(UIImage*)[list.toArray() objectAtIndex:0];
this.Add(ctlAnimations);
[self performSelector:#selector(startAnimatingImage) afterDelay:0.1];
Create a private method named startAnimatingImage with below code
self.ctlAnimations.AnimationImages = list.ToArray();
ctlAnimations.AnimationDuration = 1.0 * list.Count;
ctlAnimations.StartAnimating();
On a brief we just shown first image for a moment when the firstanimation is taken place and then we delayed animation start for 1 second so that it performs after first animation and then starts animating the image.
Go ahead and give it a try
There is the concept for the Main thread. So UIAnimation are actually works on Main Thread and at the same time may be this was happen that another task is performing on the same Main Thread.So that was a case like IOS will give preference according to processes id of each process at a time and for the solution you need to make background thread for the same operations.
Well, I never figured out what the problem was here, but it also turned out that there was some sort of memory leak in UIImage such that on some phones my code was crashing.
So I rewrote it to do the animation manually. Now I set a timer and keep a frame index variable, and every time the timer rings I change the image myself. This amounts to the same thing, and it turns out it fixes this problem.
I'm experiencing long delays (1-3 seconds) between the calls to viewWillAppear and viewDidAppear.
This happens after loading a large view, sometimes printing wait_fences as well.
No connection to UIAlertView or any of the other causes I see in related questions.
There isn't anything going on in viewWillAppear, calling super and not performing any animations.
What could be the reason for this long delay?
I've experienced exactly the same thing.
I had a tableview with an image in each cell.
I preload the images into an array but was still having this weird delay between these calls.
Making the images smaller (from full camera size to 36X36) when put into the array did the trick.
I think the delay is just the UI loading all the elements.
Make your elements more efficient.
Is there any significant difference in performance when you call
[someObject performSelector:#selector(testMethod:) withObject:anotherObject];
vs
[someObject testMethod:anotherObject];
?
The first causes an extra call to objc_msgSend() that isn't necessary in the second case.
The performance difference is unlikely to remotely matter unless you are calling said method as quickly as you possibly can many 10s of thousands of times and you aren't doing any significant work in testMethod:.
I.e. don't worry about it unless you measure an actual performance problem.
Interesting fact, performing a selector with a delay of 0 causes that method to be called at the top of the next run loop of the app. You can use that to delay certain events that occur frequently (used a lot in optimizations of UI, like images that get reloaded in a UIScrollView)
No there isn't any performance hit that I am aware of, and if there is any it is not significant.
I’ve come across an important difference when passing data to another view controller in prepareForSegue.
using:
[viewController performSelector:#selector(aMethod:) withObject:anObject];
aMethod is called AFTER viewDidLoad and viewWillAppear of the destination viewController.
using:
[viewController aMethod: anObject] ;
aMethod is called BEFORE viewDidLoad and viewWillAppear of the destination viewController.
So if you’re sending data important for the setup of the destination viewController, use the second way.
There is a lot difference in above both methods. I was trying to get animation of Two buttons coming from right side and stops at center but the second button was coming with 0.3 second delay. Now the main point comes here. I was using one animation method for both of 2 buttons. Now i wanted that when I click Finish button, then both buttons should go to left and again New buttons come. This was fine till reading.
Now when i was writing method for Finish button click. I was performing going out of buttons Animation first and then coming in buttons, but when I used the Above second method i.e. [someObject testMethod:anotherObject]; then what happens is I was not able to see the Going out Animation and directly coming in animation of buttons was shown.
Here actually comes the use of first method i.e. [someObject performSelector:#selector(testMethod:) withObject:anotherObject withDelay:delay];
The reason I found was when I click the Finish button the animation runs in different thread and the other code runs in different thread so the going out action was performed in another thread and coming in was performed in another thread. So first thread was not shown.
After using first method with Delay time of total animation. I achieved my goal. So both methods have their own significance.
For my experience,there are two differences:
The first one can add afterDelay:(CGFloat)seconds, and this is the only case I use the first one.
[someObject performSelector:#selector(testMethod:) withObject:anotherObject afterDelay:1.0];
The second one, you need to define it in someObject.h. Otherwise, you will get a compile warning.
The answer is that they are exactly the same.
There are two really good articles one from Mike Ash, where he explains the objc_msgSend():
http://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html
And an another one from Tom Dalling who is explaining that perform selector is calling objc_msgSend().
http://tomdalling.com/blog/cocoa/why-performselector-is-more-dangerous-than-i-thought/
I am trying to create an intro animation for my iOS app and am having issues with timing. In particular I would like to change screens after the intro animation plays. I currently use a UIImageView and there does not appear to be a way to do this. Many stackoverflow questions say to use an NSTimer or performSelector:afterDelay but these are not accurate timers and in my case are completely wrong. Here is what I am doing.
Set UILaunchImageFile to LaunchImage.png
AppDelegate allocs an IntroViewController
IntroViewController.LoadView allocs IntroView
IntroView.initWithFrame performs the following
UIImageView* iv =
iv.animationImages =
iv.animationDuration = 2.0
iv.animationRepeatCount = 1
[iv startAnimating]
Set NSTimer/performSelector:afterDelay?
When timer triggers change from IntroViewController to something else.
If I perform either step 5 or 6 it does not work correctly. It does correctly play the animation and it will correctly change the view/view controller, but the timing is horribly horribly wrong. When you call startAnimating in this manner it may not actually start the animation for a full second or two. I presume because the app is still loading in resources somehow. This time however is not consistent across the simulator or all devices. Infact several runs on the same device may have different results. Thus I can not hard code some delay.
All I want to do is detect that a UIImageView animation has played the last frame and do something. That's it. The best solution I've found so far is to set a timer in some manner and then do something, but in my situation a timer is not a solution.
Any ideas?
The long delay you observe is due to reading and decoding the images, which UIImageView does before the animation begins.
Core Animation performs the animation for you, and it does its drawing in the render server, which is in a separate process. Remember that what you see on the screen doesn't necessarily represent your app's instantaneous picture of your layer tree: Core Animation Rendering Architecture.
UIImageView doesn't provide facilities to give you accurate results here. I'd suggest:
Make a UIView of your own.
Create a CAKeyframeAnimation with discrete calculation mode and your images' CGImageRefs as its values.
Set the animation's delegate to your IntroViewController.
Add the animation to your view's layer for the "contents" key.
Your IntroViewController will get animationDidStop:finished: when it's done.
Two things to consider, though:
First, you'll get better results using a movie rather than a series of images, since the movie can be streamed from storage.
Second, and more importantly, this solution will improve the timing situation but will not totally mitigate it. animationDidStop:finished: is called when your app thinks the animation is done… which is not necessarily exactly when it appears to finish.
You'll do better if you don't rely on delegate callbacks for media timing: instead, add this animation and the animation transitioning your views (using a CAAnimationGroup if necessary) in the same turn of the run loop. Delay the latter with a beginTime of the first animation's duration. Depending on what you're doing, you may have to set the second animation's fill mode as well to get the correct behavior during the first.