代码之家  ›  专栏  ›  技术社区  ›  LoganHenderson

Swift中的协议设计

  •  2
  • LoganHenderson  · 技术社区  · 7 年前

    我有一个视图控制器类,可以在多个屏幕上重用,在不同的屏幕上,我想提供不同的数据源。我的VC看起来像这样:

    class SpotViewController: UIViewController {
    
        var dataSource: SpotDataSource!
    }
    

    现在我想有两个不同的数据源类

    class PersonalSpotDataSource {}
    class ExploreSpotDataSource {}
    

    现在,我想创建某种共享协议,使上述两个类实现以下属性

    var spots: [Spot]
    var title: String
    

    然后我想让这个共享的构造符合UITableViewDataSource,因为它拥有它所需要的一切,只是一系列的点和标题。然后回到我的第一节课,我可以提供任何一节课(个人课或探索课)作为VC的数据源。

    这可能吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Rob Md Fahim Faez Abir    7 年前

    因此,首先定义您的协议:

    protocol SpotDataSource {
        var spots: [Spot] { get }
        var title: String { get }
    }
    

    然后定义两个类以符合该协议:

    class PersonalSpotDataSource: SpotDataSource {
        let spots = [Spot(name: "foo"), Spot(name: "bar")]
        let title = "Foobar"
    }
    
    class ExploreSpotDataSource: SpotDataSource {
        let spots = [Spot(name: "baz"), Spot(name: "qux")]
        let title = "Bazqux"
    }
    

    显然,您的这些实现将比上面的更复杂,但这说明了基本思想。

    无论如何,完成后,定义 UITableViewDataSource 使用此协议的:

    class SpotTableViewDataSource: NSObject {
        let spotDataSource: SpotDataSource
    
        init(spotDataSource: SpotDataSource) {
            self.spotDataSource = spotDataSource
            super.init()
        }
    }
    
    extension SpotTableViewDataSource: UITableViewDataSource {
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return spotDataSource.spots.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SpotCell", for: indexPath) as! SpotCell
            cell.spotLabel.text = spotDataSource.spots[indexPath.row].name
            return cell
        }
    }
    

    最后,定义表视图控制器以使用 UITableViewDataSource 不管怎么说 SpotDataSource 您需要:

    class PersonalSpotTableViewController: UITableViewController {
    
        private let dataSource = SpotTableViewDataSource(spotDataSource: PersonalSpotDataSource())
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.dataSource = dataSource
        }
    
    }
    

    注意,在该表视图控制器类中,我定义了要存储的数据源属性,因为表视图控制器不保留对其数据源和/或委托的强引用,但我们希望它保持不变。

    显然,如果我们能把 UITableViewDataSource 中的方法 SpotDataSource 协议的默认实现,但遗憾的是我们不能。所以您必须创建符合 UITableViewDataSource 并使用 SpotDataSource 协议,如上所述。