编写具有一些网络活动的应用程序 我发现自己一遍又一遍地为多个视图控制器编写相同的代码只是为了显示活动指示器。
class SomeViewController: UIViewController {
let indicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
override func viewDidLoad() {
super.viewDidLoad()
// customize indicator
self.indicator.layer.cornerRadius = 10
self.indicator.center = self.view.center
self.indicator.hidesWhenStopped = true
self.indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
self.indicator.backgroundColor = UIColor(red: 1/255, green: 1/255, blue: 1/255, alpha: 0.5)
}
// MARK: - Acitivity Indicator
func startIndicatingActivity() {
DispatchQueue.main.async {
self.view.addSubview(self.indicator)
self.indicator.startAnimating()
}
}
func stopIndicatingActivity() {
DispatchQueue.main.async {
self.indicator.stopAnimating()
}
}
}
Run Code Online (Sandbox Code Playgroud)
在同一个SomeViewController类中,我可以按如下方式使用它:
@IBAction func startHeavyNetworkStuffButtonPressed(_ sender: UIButton) {
startIndicatingActivity()
doHeavyNetworkStuff() { success in
// heavy networking has finished
stopIndicatingActivity()
}
}
Run Code Online (Sandbox Code Playgroud)
只要我只需要在单个视图控制器中显示活动指示器,这就可以正常工作。但是,为每个需要此功能的视图控制器一遍又一遍地执行此操作很乏味。因为我讨厌一遍又一遍地编写相同的代码,所以我正在寻找一种解决方案,我可以在任何视图控制器中简单地调用startIndicatingActivity()(和stopIndicatingActivity()分别调用
)。
我明显的第一个想法是为这个UIViewController类编写一个扩展。UIActivityIndicatorView但是,由于我需要存储 的实例,因此Extensions may not contain stored properties出现错误。
接下来:子类化UIViewController。这适用于任何简单的视图控制器。但是,如果我需要相同的功能 a MyCustomTableViewController,我将再次需要首先从子类化UITableViewController并复制/粘贴现有代码。
在避免复制/粘贴大量代码的同时,是否有一种优雅的方法可以在任何视图控制器中调用startIndicatingActivity()/ stopIndicatingActivity()?我假设一个优雅的解决方案将涉及extension,protocol或某种形式的多重继承的方式。
这个SO线程是解决方案!事实证明,毕竟有一种方法可以使用 anextension和模拟属性来解决这个问题。
为感兴趣的读者发布完整的解决方案:
UIViewControllerextension UIViewController {
// see ObjectAssociation<T> class below
private static let association = ObjectAssociation<UIActivityIndicatorView>()
var indicator: UIActivityIndicatorView {
set { UIViewController.association[self] = newValue }
get {
if let indicator = UIViewController.association[self] {
return indicator
} else {
UIViewController.association[self] = UIActivityIndicatorView.customIndicator(at: self.view.center)
return UIViewController.association[self]!
}
}
}
// MARK: - Acitivity Indicator
public func startIndicatingActivity() {
DispatchQueue.main.async {
self.view.addSubview(self.indicator)
self.indicator.startAnimating()
//UIApplication.shared.beginIgnoringInteractionEvents() // if desired
}
}
public func stopIndicatingActivity() {
DispatchQueue.main.async {
self.indicator.stopAnimating()
//UIApplication.shared.endIgnoringInteractionEvents()
}
}
}
Run Code Online (Sandbox Code Playgroud)
// source: /sf/ask/1779874631/
public final class ObjectAssociation<T: AnyObject> {
private let policy: objc_AssociationPolicy
/// - Parameter policy: An association policy that will be used when linking objects.
public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {
self.policy = policy
}
/// Accesses associated object.
/// - Parameter index: An object whose associated object is to be accessed.
public subscript(index: AnyObject) -> T? {
get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
}
}
Run Code Online (Sandbox Code Playgroud)
我还UIActivityIndicatorView使用自定义的静态函数扩展了该类。
extension UIActivityIndicatorView {
public static func customIndicator(at center: CGPoint) -> UIActivityIndicatorView {
let indicator = UIActivityIndicatorView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
indicator.layer.cornerRadius = 10
indicator.center = center
indicator.hidesWhenStopped = true
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
indicator.backgroundColor = UIColor(red: 1/255, green: 1/255, blue: 1/255, alpha: 0.5)
return indicator
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2103 次 |
| 最近记录: |