Класс для протокола разговора в Swift
У меня есть этот тяжелый базовый подкласс класса VC UIViewController, который я пытаюсь преобразовать как vcprotocol.
Это основной виртуальный канал, который выполняет всю работу, как класс бога. Который я хотел бы разбить как vcProtocol.
Я пытаюсь сделать это разделение проблем. Не все ViewControllers должны отображать сообщение с предупреждением или сеть, не подключенную.
Например, у меня есть displayView, который я создаю в расширении протокола как вычисляемое свойство. Нет предупреждения об ошибке, но индикатор не отображается. Когда я пытаюсь отладить и сделать po acticvityIndicator
Я получаю следующую ошибку, которая указывает, что ActivityIndicator никогда не выделялся.
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x5a1012de027).
The process has been returned to the state before expression evaluation.
Фрагмент кода:
protocol vcProtocol {
var activityIndicator: UIActivityIndicatorView { get }
}
расширение протокола:
extension vcProtocol where Self: UIViewController {
var activityIndicator: UIActivityIndicatorView {
let indicator = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.gray)
indicator.hidesWhenStopped = true
indicator.style = .whiteLarge
indicator.color = .red
indicator.backgroundColor = UIColor.gray
indicator.translatesAutoresizingMaskIntoConstraints = false
return indicator
}
func showLoadingIndicator() {
activityIndicator.startAnimating()
activityIndicator.isHidden = false
}
func hideLoadingIndicator() {
activityIndicator.stopAnimating()
activityIndicator.isHidden = true
}
}
Я не могу обернуть голову, как решить эту проблему. поскольку я могу иметь только вычисленные свойства в протоколе. поэтому я их так же получаю только свойства. Мой план состоит в том, чтобы использовать расширение протокола для обеспечения реализации по умолчанию.
Есть мысли о том, как решить эту проблему.
1 ответ
Это activityIndicator
является вычисляемым свойством, поэтому каждый раз, когда вы ссылаетесь на вычисленное свойство, get
Блок будет называться. Чистый эффект заключается в том, что, как написано, каждый раз, когда вы ссылаетесь activityIndicator
, вы собираетесь получить новый экземпляр UIActivityIndicatorView
что, очевидно, не ваше намерение.
Считай свой showLoadingIndicator
:
func showLoadingIndicator() {
activityIndicator.startAnimating()
activityIndicator.isHidden = false
}
Первая строка (с startAnimating
) вернет новый UIActivityIndicatorView
и вторая строка (с isHidden
вернется еще один. И ни один из них не будет тем, который вы предположительно добавили в свое подпредставление.
это activityIndicator
действительно должен быть создан один раз и только один раз. К сожалению, вы не можете определить хранимое свойство в расширении, поэтому есть несколько подходов:
Вы можете позволить
UIViewController
объявите сохраненное свойство и просто определите методы для его настройки, отображения и скрытия:protocol LoadingIndicatorProtocol: class { var loadingActivityIndicator: UIActivityIndicatorView? { get set } } extension LoadingIndicatorProtocol where Self: UIViewController { func addLoadingIndicator() { let indicator = UIActivityIndicatorView(style: .gray) indicator.hidesWhenStopped = true indicator.style = .whiteLarge indicator.color = .red indicator.backgroundColor = .gray indicator.translatesAutoresizingMaskIntoConstraints = false view.addSubview(indicator) // you might want to add the constraints here, too loadingActivityIndicator = indicator } func showLoadingIndicator() { loadingActivityIndicator?.startAnimating() loadingActivityIndicator?.isHidden = false } func hideLoadingIndicator() { loadingActivityIndicator?.stopAnimating() loadingActivityIndicator?.isHidden = true } }
А потом
UIViewController
подкласс просто должен определить свой собственный ivar дляactivityIndicator
например,class ViewController: UIViewController, LoadingIndicatorProtocol { var loadingActivityIndicator: UIActivityIndicatorView? override viewDidLoad() { super.viewDidLoad() addLoadingIndicator() } ... }
Другой подход заключается в использовании связанных объектов через
objc_getAssociatedObject
а такжеobjc_setAssociatedObject
для достижения сохраненного свойства поведения:protocol LoadingIndicatorProtocol { var loadingActivityIndicator: UIActivityIndicatorView { get } } private var associatedObjectKey = 0 extension LoadingIndicatorProtocol { var loadingActivityIndicator: UIActivityIndicatorView { if let indicatorView = objc_getAssociatedObject(self, &associatedObjectKey) as? UIActivityIndicatorView { return indicatorView } let indicator = UIActivityIndicatorView(style: .gray) indicator.hidesWhenStopped = true indicator.style = .whiteLarge indicator.color = .red indicator.backgroundColor = .gray indicator.translatesAutoresizingMaskIntoConstraints = false objc_setAssociatedObject(self, &associatedObjectKey, indicator, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) return indicator } func showLoadingIndicator() { loadingActivityIndicator.startAnimating() loadingActivityIndicator.isHidden = false } func hideLoadingIndicator() { loadingActivityIndicator.stopAnimating() loadingActivityIndicator.isHidden = true } }