繁体   English   中英

快速正确使用协议扩展

[英]Swift proper use of protocol extension

我正在尝试提取一些代码库以供重用。 我的方法是使用ProtocolProtocol Extension而不是一般的BaseClass

我在下面创建了一个protocolprotocol extension

protocol MovieDisplay {

    var collectionView: UICollectionView! { get set }
    var refreshControl: UIRefreshControl! { get set }

}

extension MovieDisplay where Self: UIViewController {

    var refreshControl: UIRefreshControl {
        let rc = UIRefreshControl()
        rc.backgroundColor = .clear
        rc.tintColor = .lightGray
        if #available(iOS 10.0, *) {
            collectionView.refreshControl = rc
        } else {
            // Fallback on earlier versions
            collectionView.addSubview(rc)
        }
        return rc
    }

}

在采用协议的主类中,我这样声明(使用refreshcontrol默认实现)

class PopularMovieVC: UIViewController, MovieDisplay {

    @IBOutlet weak var collectionView: UICollectionView!

}

问题是涉及refreshcontrol功能不起作用。 仅当我在主类中显式声明refreshcontrol变量并将扩展转换为函数并在主类内调用它时,它才起作用,如下所示:

func setupRefreshControl() {
            refreshControl.backgroundColor = .clear
            refreshControl.tintColor = .lightGray
            if #available(iOS 10.0, *) {
                collectionView.refreshControl = refreshControl
            } else {
                // Fallback on earlier versions
                collectionView.addSubview(refreshControl)
            }
}

如何为默认实现正确配置protocolprotocol extension

它不起作用,因为未隐式调用计算属性。

viewDidLoad添加此行应初始化刷新控件

_ = refreshControl

在这种情况下,我真的更喜欢基类

您的协议需要一个可获取和可设置的refreshControl (返回UIRefreshControl! ),但是您的默认实现仅提供一个getter(并且该getter返回另一个类型UIRefreshControl )。 您的默认实现在每次访问它时还返回一个不同的UIRefreshControl ,并在每次访问它时修改collectionView 我想这些都不是您的意思。

正如vadian所说,如果您想自动修改collectionView.refreshControl ,我想这里就是基类。 遵守协议绝不应引起其他属性的隐式更改,并且在大多数情况下不会。 试想一下,如果PopularMovieVC都符合MovieDisplay在另一个模块的扩展。 充其量只会导致混乱。

协议一致性扩展了类型的使用方式,例如添加新方法。 它不会改变类型本身。 如果要更改类型本身的内容,则需要继承或组合之类的东西,而不是协议一致性的东西。


如果您要这样做,我不会以这种方式使用协议。 我只是创建这样的扩展:

extension UIRefreshControl {
    static func makeStandard(attachedTo collectionView: UICollectionView) -> UIRefreshControl {
        let rc = UIRefreshControl()
        rc.backgroundColor = .clear
        rc.tintColor = .lightGray
        if #available(iOS 10.0, *) {
            collectionView.refreshControl = rc
        } else {
            // Fallback on earlier versions
            collectionView.addSubview(rc)
        }
        return rc
    }
}

extension UIActivityIndicatorView {
    static func makeStandard() -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: .gray)
    }
}

然后,您的视图控制器可能如下所示:

class MyViewController: UIViewController {
    private var refreshController: UIRefreshControl!
    @IBOutlet var collectionView: UICollectionView!
    let activityIndicator = UIActivityIndicatorView.makeStandard()

    override func viewDidLoad() {
        refreshController = .makeStandard(attachedTo: collectionView)
    }
}

无需协议,这使您可以在同一个视图控制器中或其他任何异常情况下处理多个集合视图。 它还使调用此方法将修改集合视图变得更加清楚。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM