Class 到 swift 中的协议对话
Class to protocol conversation in swift
我有一个 UIViewController 的重 basicVC Class subclass,我正在尝试将其转换为 vcprotocol。
它是像上帝一样做所有工作的基本 VC class。我想将其分解为 vcProtocol。
我正在尝试做的是关注点分离。并非所有 ViewController 都需要显示警报视图或网络未连接消息。
例如,我有在计算 属性 协议扩展中创建的 indicatorView。没有错误警告,但没有显示任何指示器。当我尝试调试并执行 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
}
}
我不知道如何解决这个问题。因为我只能在协议中计算属性。
所以我将它们作为只获取属性。
我的计划是使用协议扩展来提供默认实现。
关于如何解决这个问题的任何想法。
这个 activityIndicator
是一个计算的 属性,所以每次你引用计算的 属性 时,都会调用那个 get
块。最终效果是,如所写,每次引用 activityIndicator
时,您将获得 UIActivityIndicatorView
的新实例,这显然不是您的意图。
考虑一下你的 showLoadingIndicator
:
func showLoadingIndicator() {
activityIndicator.startAnimating()
activityIndicator.isHidden = false
}
第一行(startAnimating
)将 return 一个新的 UIActivityIndicatorView
,第二行(isHidden
)将 return 另一个。而且这些都不是您可能添加到子视图中的那个。
这个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
子类只需为 activityIndicator
定义自己的 ivar,例如
class ViewController: UIViewController, LoadingIndicatorProtocol {
var loadingActivityIndicator: UIActivityIndicatorView?
override viewDidLoad() {
super.viewDidLoad()
addLoadingIndicator()
}
...
}
另一种方法是使用associated objects via objc_getAssociatedObject
and 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
}
}
我有一个 UIViewController 的重 basicVC Class subclass,我正在尝试将其转换为 vcprotocol。
它是像上帝一样做所有工作的基本 VC class。我想将其分解为 vcProtocol。
我正在尝试做的是关注点分离。并非所有 ViewController 都需要显示警报视图或网络未连接消息。
例如,我有在计算 属性 协议扩展中创建的 indicatorView。没有错误警告,但没有显示任何指示器。当我尝试调试并执行 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
}
}
我不知道如何解决这个问题。因为我只能在协议中计算属性。 所以我将它们作为只获取属性。 我的计划是使用协议扩展来提供默认实现。
关于如何解决这个问题的任何想法。
这个 activityIndicator
是一个计算的 属性,所以每次你引用计算的 属性 时,都会调用那个 get
块。最终效果是,如所写,每次引用 activityIndicator
时,您将获得 UIActivityIndicatorView
的新实例,这显然不是您的意图。
考虑一下你的 showLoadingIndicator
:
func showLoadingIndicator() {
activityIndicator.startAnimating()
activityIndicator.isHidden = false
}
第一行(startAnimating
)将 return 一个新的 UIActivityIndicatorView
,第二行(isHidden
)将 return 另一个。而且这些都不是您可能添加到子视图中的那个。
这个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
子类只需为activityIndicator
定义自己的 ivar,例如class ViewController: UIViewController, LoadingIndicatorProtocol { var loadingActivityIndicator: UIActivityIndicatorView? override viewDidLoad() { super.viewDidLoad() addLoadingIndicator() } ... }
另一种方法是使用associated objects via
objc_getAssociatedObject
andobjc_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 } }