Is there any method that will execute prior to - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration?
This is very important to me because it seems like the view coordinate system switches immediately before this method is executed. I am trying to execute a method immediately before the system has decided to rotate the device, so something along the lines of - (BOOL)shouldAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation would seem to be the perfect place to execute such a method (but it doesn't seem to exist in the documentation).
Thank you!
The method you are looking for is willRotateToInterfaceOrientation:duration:. The bounds have not been transformed at the time it is called.
But:
These methods are deprecated in iOS 8 (and the entire "rotation" model is completely changed), so don't become reliant upon them.
In my view it would be better ask yourself why you think you need the view coordinate system in this way. It would be better to position things using constraints that are independent of such considerations.
Related
Does anyone know why UITextView.layoutSubviews() is not called when rotating a device to portrait mode?
When rotating to landscape mode, these are called:
UIViewController.viewWillTransition
UIViewController.viewDidLayoutSubviews
UITextView.layoutSubviews
UILabel.layoutSubviews
But when rotating back to portrait, the UILabel.layoutSubviews() is called, but not the UITextView.layoutSubviews. This is in an empty project with no other code apart from traces in these methods.
layoutSubviews is usually called when setNeedsLayout() is invoked already in the previous invocation of run loop.
If the layout system does not think it needs to be called, it will not be called.
Ideally you should not override this function. You should just call setNeedsLayout() after making superview changes, and let the layout system call the default implementation of this function. Morever, you should define your subview layout needs inside auto-layout so it is able to get correct values from there.
If you want immediate update, you should call layoutIfNeeded().
This is because this is one of those methods that are called arbitrarily by UIKit framework and it may not be ideal for your layout needs.
There are 2 separate things here.
Understanding layoutSubviews(). I.e. when and where to use it.
How to achieve what you want to do the right way. I.e. doing something with the UITextView at device rotation.
About the layoutSubviews(), you should not put any logic here as your view is not having any sub views.
You may say that we expect iOS to call it, so we can put some implementation here, but again, that is not the right way. layoutSubviews() is not meant to alter the view itself, but just laying out sub views.
I would recommend reading more on layoutSubviews(). I learnt from here, when I started learning iOS.
Now to achieve what you want to do, i.e. do something at the time of device rotation, you proper way is to use viewWillTransition(to:with:) method of UIViewController.
In this method, you can put logic to do something just before the transition will happen.
And you can also put logic which will execute during the transition OR after the transition completes, using the UIViewControllerTransitionCoordinator parameter passed to viewWillTransition(to:with:)
Hope this helps!
This sounds terrible in practice, but I want to leverage the Xcode Injection plugin/app and have a quick way to refresh the currently visible view controller to apply changes.
So for instance, if I set up certain variables in init, certain in viewDidLoad, others in viewDidAppear, I'd like those all to be called again. Simply manually calling viewDidLoad unfortunately doesn't accomplish all of this.
Any ideas?
I placed my code for iAd/AdMob ads in...
-(void)viewWillAppear:(BOOL)animated{}
Ads work perfectly fine the way I have them now on all iOS devices.
When I connected my iPhone to Xcode and clicked on Product -->Analyze a message states...
The viewWillAppear:instance method in UIViewController subclass 'iPhoneSIX' is missing a [super viewWillAppear:] call
I just accidentally stumbled upon this Product-->Analyze thing. Do I really need to add [super viewWillAppear] even though everything works perfectly fine on all devices as it currently is. Will Apple reject my app if I don't pay attention to the Product-->Analyze issue navigator?
Also, what does ...
[super viewWillAppear:YES];
What does calling this do?
According to Apple: (emphasis mine)
This method is called before the receiver's view is about to be
added to a view hierarchy and before any animations are configured for
showing the view. You can override this method to perform custom tasks
associated with displaying the view. For example, you might use this
method to change the orientation or style of the status bar to
coordinate with the orientation or style of the view being presented.
If you override this method, you must call super at some point in your
implementation.
Apple doesn't gets that specific when deciding to Accept or Reject your app. It only follows the guidelines, which doesn't get that much into the weeds of your specific methods.
Calling [super viewWillAppear:YES] is a best practice, and I would recommend it. Always including super ensures that any code in the super classes get called before executing any additional code. So if you or someone else coded a super class that expected some code to be executed, you are guaranteed to still execute it, rather than just overwriting the whole method in the subclass.
Say you have a view controller of type MyViewController which is a subclass of UIViewController. Then say you have another view controller of type MyOtherViewController, which is a subclass of MyViewController. Say you're coding now some things in viewWillAppear in MyOtherViewController. If you call super first, it will call viewWillAppear in MyViewController before executing any code. If viewWillAppear in MyViewController calls super first, then it will call viewWillAppear in UIViewController before executing any code.
I'm quite certain Apple will not reject your app for failing to call super on an overridden method, primarily because there are cases where you may specifically want to avoid calling super.
That said, as Josh Gafni mentions it is definitely a best practice to do so, unless you have a very good reason for not. Also bear in mind some view controller subclasses (can't recall specifically which ones, but maybe UICollectionViewController) will only work properly if their view lifecycle methods get called appropriately, so not calling super can definitely break some classes (sometimes in subtle ways you may not realize).
Therefore my suggestion is add the call to super (generally as the first line in the method) and see if things continue to work fine. If not, spend a bit of time trying to understand what is happening differently and see if you can solve it in a different way. In general you should always (as a force of habit) provide calls to super on any view lifecycle methods you override whenever possible.
Actually this is a simple question with maybe not an answer for a central solution.
I would like a way to monitor in a central way every UIView start-finish loading to get metrics of the application.
I can see that viewWillLoad doesn't exist anyway in the UIViewController class and viewWillAppear is not something that it could serve the purpose.
Is this feasible in any way? I'm thinking of searching every UIView inherited class in the application and inject code somehow, but as I said I will need two methods.
Or maybe inject code to a protocol that already exists in the UIView class?
Any thoughts?
Regards.
If you are only concerned with the loading of the root view of every view controller. You could swizzle -loadView and -viewDidLoad of UIViewController. You could exchange those with methods that add start and end times to a table for each instance that calls them. Keep in mind though, that just the act of measuring it, you are going to slow down the loading.
If you want to track the loading of every view, you could swizzle -initWithFrame on UIView in the same way. In your version of the method you would start tracking before you call the real version and stop tracking once the real method has exited. However, if you have custom views that have their own initializers you will have to come up with a more complex version of that. However I do not recommend doing this. The time it takes to initialize a view is probably less time or at least very close to the amount of time it will take to track it making the timings worthless.
Is there any possible way to detect every change on User Interface during runtime??
I'm trying to find all objects in the current app interface.
I'm trying to to get all nodes inspecting recursively the main Window, but, for example, how to know if the top viewcontroller changes or if it's added a uiview dynamically, or is presented a modalview??
The main objective is to have a library to do this..
Any idea, help?
Thanks!
You could write your own library based on this, using advanced Objective-C techniques. I do not recommend you to do this, since it mostly breaks MVC patterns on iOS. Depends on what do you want to use it for, maybe analytics?
So these are the options I believe, if you want to actively inspect UIView hierarchy. All options are pretty complicated though.
Swizzle methods such as addSubview and removeFromSuperview of UIView, so you could know when changes like that happens. Including the getters of frame and bounds, if you wish to know the position.
You could use KVO to watch properties such as: subviews, frame, bounds, superview to notice any changes. But at one point you would have to add the same object as the observer (could be singleton).
Decide for an interval that is fired by a NSTimer and go through the hierarchy recursively beginning at keyWindow on UIApplication. This would have a big performance impact though.
There may be other options, but these are the ones I believe to be the best choices.