Why do we need to set delegate to self? Why isn't it defaulted by the compiler?

前端 未结 3 1127
野趣味
野趣味 2021-01-17 08:13

I think I fully understand the concept of delegation, my question is that when we do:

class someViewController : UIViewController, UITableViewDelega         


        
3条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-17 09:04

    would it ever be possible that we wouldn't want to set tableView.delegate to self

    Yes, if you would implement datasource and delegate in it's own class.

    why is Xcode forcing us to do some extra work here?

    to allow as much freedom in our architectures as possible.


    An example with separate classes for datasource and delegate.

    class TableViewDatasource: NSObject, UITableViewDataSource {
        // implement datasource
    }
    
    class TableViewDelegate : NSObject, UITableViewDelegate {
        // implement delegate
    }
    
    class ViewController: UIViewController {
    
         IBOutlet weak var tableView: UITableView! {
             didSet {
                  tableView.dataSource = tableViewDatasource
                  tableView.delegate = tableViewDelegate
             }
         }
    
         let tableViewDatasource = TableViewDatasource()
         let tableViewDelegate = TableViewDelegate()
    
    }
    

    This allows higher reusability and favours composition over inheritance, if you'd allow view controllers to hold different implementations of delegate and datasource.

    You deal with smaller classes and those are easier to test and maintain.

    It is even possible to design complete apps, that don't need any view controller subclasses.


    datasource/delegate design can be as sophisticated as you like.

    As an example I want to show you a new project of mine: TaCoPopulator. It is a framework to populate table view and collection views transparently by splitting it up in distinct task to follow the SOLID Principles:

    import UIKit
    
    class CollectionViewController: UIViewController {
    
        @IBOutlet weak var collectionView: UICollectionView!
        private var datasource: ViewControllerDataSource?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.datasource = ViewControllerDataSource(with: collectionView)
        }
    }
    

    import UIKit
    
    class TableViewController: UIViewController {
    
        @IBOutlet weak var tableView: UITableView!
        private var datasource: ViewControllerDataSource?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.datasource = ViewControllerDataSource(with: tableView)
        }
    }
    

    import TaCoPopulator
    
    
    class IntDataProvider: SectionDataProvider {
    
        override init(reuseIdentifer: @escaping (Int, IndexPath) -> String) {
            super.init(reuseIdentifer: reuseIdentifer)
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
                self.provideElements([1,2,3,4,5,6,7,8,9])
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
                    self.provideElements(self.elements() + [10, 11, 12, 13, 14, 15])
                }
            }
        }
    }
    

    import TaCoPopulator
    
    
    class ViewControllerDataSource {
        init(with populatorView: PopulatorView) {
            self.populatorView = populatorView
            setup()
        }
    
        var intSelected: ((Int, IndexPath) -> Void)?
        var stringSelected: ((String, IndexPath) -> Void)?
    
        let dp1 = IntDataProvider {
            _ in return "Cell"
        }
    
        let dp2 = StringDataProvider {
            _ in return "Cell"
        }
    
    
        weak var populatorView: PopulatorView?
        var populator: Populator?
    
        func setup(){
            dp1.selected = {
                [weak self] element, indexPath in
                self?.intSelected?(element, indexPath)
            }
    
            dp2.selected = {
                [weak self] element, indexPath in
                self?.stringSelected?(element, indexPath)
            }
    
            let collectionViewCellConfig: (Any, TextCollectionViewCell, IndexPath) -> TextCollectionViewCell  = {
                element, cell, _ in
                cell.textLabel?.text = "\(element)"
                return cell
            }
    
            let tableViewViewCellConfig: (Any, UITableViewCell, IndexPath) -> UITableViewCell  = {
                element, cell, _ in
                cell.textLabel?.text = "\(element)"
                return cell
            }
    
            if  let populatorView  = populatorView as? UICollectionView {
                let  section1factory = SectionCellsFactory(parentView: populatorView, provider: dp1, cellConfigurator: collectionViewCellConfig)
                let  section2factory = SectionCellsFactory(parentView: populatorView, provider: dp2, cellConfigurator: collectionViewCellConfig)
                self.populator = Populator(with: populatorView, sectionCellModelsFactories: [section1factory, section2factory])
            }
    
            if  let populatorView  = populatorView as? UITableView {
                let section1factory = SectionCellsFactory(parentView: populatorView, provider: dp1, cellConfigurator: tableViewViewCellConfig)
                let section2factory = SectionCellsFactory(parentView: populatorView, provider: dp2, cellConfigurator: tableViewViewCellConfig)
                self.populator = Populator(with: populatorView, sectionCellModelsFactories: [section1factory, section2factory])
            }
        }
    
    }
    

提交回复
热议问题