#ios #swift #extension-methods #inout
#iOS #swift #методы расширения #inout
Вопрос:
Мне нужно переместить метод для добавления и удаления представления журнала внутри расширения, чтобы передать его каждому контроллеру. для этого я добавил параметр inout UIVew в исходный метод, где я использовал глобальную переменную для представления. нет, у меня эта ошибка
Значение типа ‘UIViewController’ не имеет члена ‘containerForLoading’
удаление self из self.containerForLoading
приведет к ошибке:
Экранирующее закрытие фиксирует параметр ‘inout’ ‘containerForLoading’
внутри анимированного закрытия (см. Комментарий) все неправильно во всем процессе или я заблудился на последнем шаге?
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()
}
}
это код внутри исходного ViewController
использование этого параметра
var containerForLoading = UIView()
вызывается таким образом, когда это необходимо
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()
}
}
Комментарии:
1.
self.containerForLoading.alpha
вызывается внутри aextension UIViewController {}
, поэтому он ожидает, что оно будет свойствомUIViewController
. Это не так. Вы имели в виду «containerForLoading.alpha», поскольку это предыдущая переменная, которую вы хотите.2. но я не могу удалить self или я получаю ошибку при экранировании замыкания, которая захватывает параметр ‘inout’, параметр ‘containerForLoading’
3. Можете ли вы показать, на что похож ваш код, прежде чем помещать его в расширение?
4. обновлено старым кодом, в основном то же самое, за исключением ввода нового параметра
Ответ №1:
Вы могли бы создать loadingContainerTag
локальную переменную и изменить имя параметра на что-то другое. Затем присвоите параметру сразу после создания представления контейнера:
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
может inout
быть только один непараметр:
func removeLoading(containerForLoadingProperty: UIView) {
containerForLoadingProperty.removeFromSuperview()
}
Но…
Очень странно, что методу, который показывает индикатор загрузки, нужен inout
параметр. Оно не должно присваиваться специальному свойству, предоставляемому вызывающим объектом. Он должен просто показывать индикатор загрузки!
Цель вашего containerForLoading
свойства заключается в том removeLoading
, чтобы вы знали, какое представление удалить. Если вы не сохраните containerForLoading
представление где-нибудь в свойстве, вы не будете знать, какое представление удалить, верно? Ну, мы можем использовать tag
свойство представления для идентификации представлений, поэтому вы можете просто создать containerForLoading
локальную переменную, а позже removeLoading
использовать ее тег, чтобы найти ее.
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()
}
}
Комментарии:
1. спасибо, кажется, это работает! Я хотел бы знать, возможно ли такое же достижение с помощью расширения протокола, есть ли какие-то проблемы с сохраненными свойствами, верно?
2. Да, нет простого способа добавить сохраненные свойства в расширение. Если бы это было так, вы могли бы добавить
UIView
свойство для хранения загрузочного контейнера.