gpt4 book ai didi

ios - Swift 协议(protocol)关联类型和继承约束

转载 作者:可可西里 更新时间:2023-11-01 00:48:33 25 4
gpt4 key购买 nike

我想用 UICollectionViewController 构建一个 iOS 应用程序每行始终具有相同数量的单元格。因为我不想要我的 UICollectionViewController为了处理太多事情,我重构了我的代码并实现了一些有趣的事情,比如 protocol associatedtype和通用类型。现在,我的应用程序由 4 个不同的 .swift 组成文件。


1。 CustomFlowLayout.swift

CustomFlowLayoutUICollectionViewFlowLayout 的简单子(monad)类这允许我们设置它的 minimumInteritemSpacing , minimumLineSpacingsectionInset由于方便的初始化程序,具有依赖注入(inject)的属性。

import UIKit

class CustomFlowLayout: UICollectionViewFlowLayout {

convenience init(minimumInteritemSpacing: CGFloat = 0,
minimumLineSpacing: CGFloat = 0,
sectionInset: UIEdgeInsets = .zero) {
self.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
}

override init() {
super.init()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

2。 ColumnDataSource.swift

ColumnDataSourceNSObject 的子类符合 UICollectionViewDataSource , UICollectionViewDelegateUICollectionViewDelegateFlowLayout .它的工具collectionView(_:layout:sizeForItemAt:)为了显示正确数量的UICollectionViewCell每行 s。另请注意 ColumnDataSource是一个泛型类,需要我们在初始化时向它传递一个类型参数。

import UIKit

class ColumnDataSource<FlowLayoutType: UICollectionViewFlowLayout>: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

let cellsPerRow: Int

init(cellsPerRow: Int) {
self.cellsPerRow = cellsPerRow
super.init()
}

// MARK: - UICollectionViewDataSource

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
}

// MARK: - UICollectionViewDelegateFlowLayout

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let flowLayout = collectionView.collectionViewLayout as! FlowLayoutType
let marginsAndInsets = flowLayout.sectionInset.left + flowLayout.sectionInset.right + flowLayout.minimumInteritemSpacing * (CGFloat(cellsPerRow) - 1)
let itemWidth = (collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)
return CGSize(width: itemWidth, height: itemWidth)
}

}

3。 ColumnFlowLayoutable.swift

ColumnFlowLayoutable的目的|协议(protocol)是为了确保任何符合它的类都有columnDataSourcecustomFlowLayout columnDataSource 的属性类型的类型参数匹配 customFlowLayout类型。

import UIKit

protocol ColumnFlowLayoutable {

associatedtype FlowLayoutType: UICollectionViewFlowLayout
var columnDataSource: ColumnDataSource<FlowLayoutType> { get }
var customFlowLayout: FlowLayoutType { get }

}

4。 CollectionViewController.swift

CollectionViewControllerUICollectionViewController 的子类符合 ColumnFlowLayoutable协议(protocol)。它还实现了 viewWillTransition(to:with:)以应对容器尺寸的变化。

import UIKit

class CollectionViewController: UICollectionViewController, ColumnFlowLayoutable {

let columnDataSource = ColumnDataSource<CustomFlowLayout>(cellsPerRow: 2)
let customFlowLayout = {
CustomFlowLayout(minimumInteritemSpacing: $0, minimumLineSpacing: $0, sectionInset: UIEdgeInsets(top: $0, left: $0, bottom: $0, right: $0))
}(10)

override func viewDidLoad() {
super.viewDidLoad()

collectionView?.collectionViewLayout = customFlowLayout
collectionView?.dataSource = columnDataSource
collectionView?.delegate = columnDataSource
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionView?.collectionViewLayout.invalidateLayout()
}

}

完整的项目可以在这个 Github 存储库中找到:CollectionViewColumnsProtocol .


这段代码工作正常。我可以将它与 CustomFlowLayout 的子类一起使用它仍然有效。 但是,我不能将它用于 ColumnDataSource 的子类.

如果我尝试使用 ColumnDataSource 的子类构建项目(例如 class SubColumnDataSource: ColumnDataSource<CustomFlowLayout> )在 CollectionViewController 中, Xcode 抛出以下构建时错误消息:

Type 'CollectionViewController' does not conform to protocol 'ColumnFlowLayoutable'

我必须在 ColumnFlowLayoutable 中更改什么?协议(protocol)为了允许 CollectionViewController使用 ColumnDataSource 的子类?

最佳答案

为您的布局类型创建一个具有关联类型的数据源协议(protocol):

protocol ColumnDataSourceProtocol: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
associatedtype Layout: UICollectionViewFlowLayout
}

使您的 DataSource 基类符合此协议(protocol)。如果编译器无法推断关联类型,您可能需要添加 typealias 来指定关联类型:

class ColumnDataSource<FlowLayoutType: UICollectionViewFlowLayout>: NSObject, ColumnDataSourceProtocol {

typealias Layout = FlowLayoutType

// the rest stays the same
}

调整 ColumnFlowLayoutable 以关联数据源类型而不是布局类型。将其约束到 ColumnDataSourceProtocol 可以让您访问其关联的 Layout 类型:

protocol ColumnFlowLayoutable {

associatedtype DataSource: ColumnDataSourceProtocol

var columnDataSource: DataSource { get }
var customFlowLayout: DataSource.Layout { get }
}

现在你可以继承ColumnDataSource:

class DataSource: ColumnDataSource<CustomFlowLayout> { /* ... */ }

关于ios - Swift 协议(protocol)关联类型和继承约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41417411/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com