I need to move a method for adding and removing a logging view inside an Extension, in order to give it to every controller. to do so I added a inout UIVew parameter to original method, where I used a global var for the view. no I have this error
Value of type 'UIViewController' has no member 'containerForLoading'
removing self from self.containerForLoading
will give error:
Escaping closure captures 'inout' parameter 'containerForLoading'
inside the animate closure (see the comment) is all wrong the entire process or I am lost at the last step?
extension UIViewController {
func showLoadingView(containerForLoading: inout UIView, uponView: UIView) {
containerForLoading = UIView(frame: uponView.bounds)
uponView.addSubview(containerForLoading)
containerForLoading.backgroundColor = .white
containerForLoading.alpha = 0
UIView.animate(withDuration: 0.24) { self.containerForLoading.alpha = 0.8 } //here the error
let activivityIndicator = UIActivityIndicatorView()
containerForLoading.addSubview(activivityIndicator)
activivityIndicator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)
])
activivityIndicator.startAnimating()
}
func removeLoading(containerForLoading: inout UiView, uponView: UIView) {
containerForLoading.removeFromSuperview()
}
}
this is the code inside the original viewController
using this var
var containerForLoading = UIView()
called this way when needed
self.showLoadingView(uponView: self.view)
extension ViewController {
func showLoadingView(uponView: UIView) {
containerForLoading = UIView(frame: uponView.bounds)
uponView.addSubview(containerForLoading)
containerForLoading.backgroundColor = .white
containerForLoading.alpha = 0
UIView.animate(withDuration: 0.24) { self.containerForLoading.alpha = 0.8 }
let activivityIndicator = UIActivityIndicatorView()
containerForLoading.addSubview(activivityIndicator)
activivityIndicator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)
])
activivityIndicator.startAnimating()
}
func removeLoading(uponView: UIView) {
containerForLoading.removeFromSuperview()
}
}
You could make loadingContainerTag
a local variable, and change the parameter name to something else. Then assign to the parameter just after you create the container view:
extension UIViewController {
func showLoadingView(containerForLoadingProperty: inout UIView, uponView: UIView) {
// local variable!
let containerForLoading = UIView(frame: uponView.bounds)
// also set property
containerForLoadingProperty = containerForLoading
uponView.addSubview(containerForLoading)
containerForLoading.backgroundColor = .white
containerForLoading.alpha = 0
// no "self."!
UIView.animate(withDuration: 0.24) { containerForLoading.alpha = 0.8 }
// ... everything else is the same
removeLoading
could just have one non-inout
parameter:
func removeLoading(containerForLoadingProperty: UIView) {
containerForLoadingProperty.removeFromSuperview()
}
But...
It is very weird for a method that shows a loading indicator, to need an inout
parameter. It shouldn't assign to a special property that the caller provides. It should just show the loading indicator!
The purpose of your containerForLoading
property is so that in removeLoading
, you know which view to remove. If you don't store the containerForLoading
view somewhere in a property, you wouldn't know which view to remove, right? Well, we can use the tag
property of a view to identify views, so you can just make containerForLoading
a local variable, and later in removeLoading
, use its tag to find it.
extension UIViewController {
static let loadingContainerTag = <a number you like>
func showLoadingView(uponView: UIView) {
// local variable!
let containerForLoading = UIView(frame: uponView.bounds)
uponView.addSubview(containerForLoading)
containerForLoading.backgroundColor = .white
containerForLoading.alpha = 0
// set tag
containerForLoading.tag = UIViewController.loadingContainerTag
// no "self."!
UIView.animate(withDuration: 0.24) { containerForLoading.alpha = 0.8 }
let activivityIndicator = UIActivityIndicatorView()
containerForLoading.addSubview(activivityIndicator)
activivityIndicator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)
])
activivityIndicator.startAnimating()
}
func removeLoading(uponView: UIView) {
// find view with the tag
uponView.viewWithTag(UIViewController.loadingContainerTag)?.removeFromSuperview()
}
}