0

我正在尝试提取一些代码库以供重用。我的方法是使用ProtocolandProtocol Extension而不是 general 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默认实现?

4

2 回答 2

1

它不起作用,因为计算的属性没有被隐式调用。

添加这一行viewDidLoad应该初始化刷新控件

_ = refreshControl

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

于 2018-11-28T18:25:31.000 回答
1

您的协议需要一个 gettable 和 settable 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)
    }
}

不需要协议,这允许您在同一个视图控制器中处理多个集合视图,或任何其他不寻常的情况。它还更清楚地表明调用此方法将修改集合视图。

于 2018-11-28T18:39:08.970 回答