The right way to write masonry code? in “- init” or “- layoutSubViews” - ios

Both ways seem to work, are there any differences in performance?

Well it really depends on what you want to do. You can call it from init but then the code will only be called when you instantiate the class. If you put it in layoutSubviews you can have the code called multiple times by making the view redraw.
So if you need to update constraints based on things changing it could be advantageous to use layoutSubviews but if you don't need to modify the constraints I would personally make a new method called setConstraints which would contain all the constraints and call that from init

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!

Where should we place our auto layout code?

I usually set all my auto layout code in the updateCOnstratins method of my view controller for the constraints of all the subclasses defining the view. Then in the subviews I place my constraints in the updateConstraints methods there. This makes me have a property of every single view in my class so I can reference it later on after I set translates.... to false. But Im reading that you don't have to set it in updateConstraints. Just not I read an article where the person says an apple engineer said that if the constraints are only made once then you can put them pretty much where ever. Yet, if you have constrains that change during the views lifecycle you place them in updateConstraints? Here are the links http://swiftandpainless.com/where-to-put-the-auto-layout-code/ http://swiftandpainless.com/dont-put-view-code-into-your-view-controller/.
So where should It go? Was this just an old way of doing this and now it has changed?
What you said in your post is what you would generally want to do. Put any constraints that might change in updateConstraints. This also means you should keep a reference to them to be able to update them or remove/replace them. Any static ones can be put after your initialization code (the init method of a UIView or the viewDidLoad method of a UIViewController, for instance). The only real requirement there is you can only add constraints to views that are actually in a view hierarchy together, so anytime after you've added the appropriate views would be fine.
There is usually no reason not to put your constraint creation code in viewDidLoad, which has the advantage of being called only once. For constraints that change, I like to associate that code with whatever directly precipitates the change, such as a change in size class or the removal or insertion of a view.

Autolayout constraints update with size classes

I know, how to create autolayout constraints with size classes perfectly.
But I am not getting when to call layOutIfNeeded(), setNeedsDisplay(), layOutSubViews(), setUpdateConstraints().
Can someone tell how to properly call this function to update UI after constraints changed.
Another my concern is, when to call only single function out of above and call with other functions.
It must be really clear that your layout is calculated by a routine that is called at specific times at runtime.
It could happen that you need to modify the current layout, for instance changing the constant of a specific constraint. If you just do that you will notice no changes in the UI, this is because the routine is still not called.
What you can do is force the layout routine to be called, and you do that by these two methods:
setNeedsLayout : You are telling that the view needs a layout. The next time the routine is called knows that this view need to have a layout refresh
layOutIfNeeded(): You don't want to wait the next call and you are telling the system to force layout calculation ASAP
Same thing happen with setNeedsDisplay() and displayIfNeeded(), with the first you tell that a view needs to be rendered again, and with the second you tell do ASAP.
If you are asking yourself why, the reason is performance. Is useless to re-render everything each time, this lazy approach will save system resources.
The methods - setNeedsUpdateConstraints and -updateConstraintsIfNeeded are basically the same concept applied to constraints, the difference is that you will not see any changes in UI until you force a layout, why this methods are useful? because sometimes you need to check after a change in constraint if the layout is still valid without changing the aspect of your UI.

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.

The right way to manage subviews in a UIControl

(iPhone SDK 3.x:) I have a UIControl subclass that creates a different number of subviews depending on the length of an NSArray property. Please take my word for it that this needs to be a UIControl rather than a UIView.
Currently I implement subview management in drawRect, beginning by removing all subviews and then creating the appropriate number based on the property. I don't think this is very good memory management and I'm not sure if drawRect is really the appropriate place to add subviews. Any thoughts on the best way to handle this pattern?
Thank you.
There is a method called layoutSubviews, and like the name already says, that method is thought to layout the subviews. You can call setNeedsLayout and the layoutSubviews method will be called (do not call layoutSubviews directly).

Resources