When to use didMoveToWindow method? - ios

I have been searching around for this particular method:didMoveToWindow() however I haven't found any concrete information.
Could someone explain why and when should someone use this method and when is it called?

This method is called by iOS when a UIView is added to the Window object.
You are supposed to override it to make your app do something at the same that.
The default implementation of this method does nothing. Subclasses can
override it to perform additional actions whenever the window changes.
The window property may be nil by the time that this method is called,
indicating that the receiver does not currently reside in any window.
This occurs when the receiver has just been removed from its superview
or when the receiver has just been added to a superview that is not
attached to a window. Overrides of this method may choose to ignore
such cases if they are not of interest.
https://developer.apple.com/reference/uikit/uiview/1622527-didmovetowindow

Related

Swift - TextView layoutSubviews() not called during viewWillTransition()

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!

Documentation on not calling viewDidLoad directly?

The [UIViewController viewDidLoad] method is called by the system after loading the associated view (obviously?). A common belief -- which I share -- is that viewDidLoad should not be called directly †. However, I can't find this guidance in the documentation, nor anything else from Apple. Does it exist?
For comparison, the loadView documentation says
You should never call this method directly.
† Excepting [super viewDidLoad] in an overridden method.
I don't think there's any rule that forbids it. I don't mean "there's a rule we all know, it's just not written down." I mean "I don't think there's any rule that forbids it." You are, as best I am aware, free to call viewDidLoad whenever appropriate (including its super).
That doesn't mean you should call it. But then you almost certainly should never call OSCompareAndSwap either. In both cases, if you had a good reason and knew what you were doing, it could be appropriate to call. But it's unlikely to come up.
While I can't think of a time I've had to call viewDidLoad directly, I have had to manually call viewWillAppear and viewDidDisappear to manage view lifecycle in a custom container view controller. There's nothing that forbids calling view lifecycle methods if that's what you mean.
That said, it would be bad practice to call a view lifecycle method if you didn't mean "the view has transitioned into this state." And since it's pretty hard to get into a situation where you have loaded the view, but viewDidLoad won't be called, it's hard to imagine many cases where it would be useful. And you shouldn't call a method uselessly. So that's the only rule at play here as far as I'm aware.
It is not mentioned explicitly but if you would call it, you would somehow violate the "contract" of the method specified in its documentation:
Called after the controller's view is loaded into memory.

touchesBegan() not being called on subviews

I have a class called SKButton, subclass of SKSpriteNode, which implements the touchesBegan() function to print("hello"). But when i add an SKButton object to my view, touchesBegan() never gets called on the button. Why?
You need to make sure that userInteractionEnabled is enabled on all of the superviews of your view.
Also keep in mind that coming from Swift 2.3 to Swift 3 in your project might trigger the warning for the name of the method, you update it using the default fix and then you end up like me wondering why the methods related to touches are not called despite of the fact that you set userInteractionEnabled. Fix: make sure that method name is written as per your current version of Swift!

Is it a MUST for viewWillAppear to have [super viewWillAppear] method as well

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.

Does willMoveToSuperview will also deallocate the UIView on which its got called?

I was wondering if I can call willMoveToSuperview on UIView and after that retain that view to reuse later for one ? something like following
if (!CGRectIntersectsRect(cell.frame, visibleRegion)) {
[cell willMoveToSuperview:nil];
[self.resuableCells addObject:cell];
}
I am not sure about your intent here...
But WillMoveToSuperview - According to doc:
The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes.
So your code,
[cell willMoveToSuperview:nil];
Has no effect unless you override this method in a cell subclass and implement your own logic there.
Coming to your question -
Does willMoveToSuperview will also deallocate the UIView on which its got called?
Answer is obvious - NO.
willMoveToSuperview is an observer method that the system calls as a courtesy to you in order to give you a chance to handle special cases before it completes some other hidden tasks.
It's default behavior is to do nothing, but you might want to tidy up something in your code prior to a move by overriding this method.
A proper use case might be if you had a view playing a video clip or an animation, and something else in your code is about to rip the view out of it's current hierarchy and place it in some other un-related view hierarchy. You might want the chance to pause the clip or suspend the animation before the move took place.
I doubt it's the right method to handle what you are attempting, and I definitely know you should not be calling it directly.
Feel free to post some more code to show us what you're trying to accomplish and where it's going wrong.

Resources