Swift 为什么我们需要将委托设置为self?为什么编译器不默认它?

Swift 为什么我们需要将委托设置为self?为什么编译器不默认它?,swift,uitableview,design-patterns,delegates,composition,Swift,Uitableview,Design Patterns,Delegates,Composition,我想我完全理解授权的概念,我的问题是,当我们这样做时: class someViewController : UIViewController, UITableViewDelegate{ } 我们是否可能不想将tableView.delegate设置为self 如果没有任何机会,那么为什么Xcode会强迫我们在这里做一些额外的工作 如果tableView.delegate有可能被设置为除self之外的其他值,那么这是什么呢?你能提供一些例子吗 有没有可能我们不想 tableView.dele

我想我完全理解授权的概念,我的问题是,当我们这样做时:

class someViewController : UIViewController, UITableViewDelegate{

}
我们是否可能不想将tableView.delegate设置为self

如果没有任何机会,那么为什么Xcode会强迫我们在这里做一些额外的工作

如果tableView.delegate有可能被设置为除self之外的其他值,那么这是什么呢?你能提供一些例子吗

有没有可能我们不想 tableView.delegate to self

是的,如果您想在自己的类中实现datasource和委托

为什么Xcode强迫我们在这里做一些额外的工作

在我们的架构中允许尽可能多的自由

一个为datasource和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()

}
如果您允许视图控制器保存委托和数据源的不同实现,那么这允许更高的可重用性,并且有利于组合而不是继承

您处理较小的类,这些类更容易测试和维护

甚至可以设计不需要任何视图控制器子类的完整应用程序

数据源/委托设计可以像您喜欢的那样复杂

作为一个例子,我想向您展示我的一个新项目:。它是一个框架,通过将表视图和集合视图拆分为不同的任务来透明地填充表视图和集合视图,以遵循以下坚实的原则:

import UIKit

class CollectionViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    private var datasource: ViewControllerDataSource<UICollectionView>?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.datasource = ViewControllerDataSource(with: collectionView)
    }
}
我们是否可能不想将tableView.delegate设置为self

什么是tableView.delegate?您的类someViewController不是UITableViewController的子类,并且没有tableView属性。它甚至不知道您处理的是表视图

您的类型声明符合UITableViewDelegate这一事实并不表明应该在哪个实际的表视图实例上设置它

如果tableView.delegate有可能被设置为除self之外的其他值,那么这是什么呢

通常,明智的做法是将功能划分为多种类型,以降低视图控制器的复杂性。您的someViewController可能有一个viewModel属性来处理与表视图有关的所有事情。

在所需的ViewController中提到tableView.delegate=self或tableView.dataSource=self时,这意味着ViewController说我负责实现这些委派/数据源方法,这意味着该ViewController自身负责提供所需的方法,以让tableView知道其外观/行为

关于你的问题:

有没有可能我们不想 tableView.delegate to self

实际上这是可能的,但这会导致tableView显示为空的tableView,其中没有行,因为没有人告诉它应该如何显示/行为

如果tableView.delegate有可能设置为其他值 比赛尔夫…那是什么?你能提供一些例子吗

是的,您可以,tableView.dataSource/delegate不需要分配给包含此tableView的同一个Viewcontroller,但我发现它更可读、更容易理解

例如:

在下面的代码片段中,我将tableView的数据源分配给另一个独立的类,该类甚至不是另一个.swift文件上的UIViewController,它完全可以正常工作:

import UIKit

// ViewController File
class ViewController: UIViewController {
    var handler: Handler!

    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()

        handler = Handler()
        tableView.dataSource = handler
    }
}
处理程序类:

import UIKit

class Handler:NSObject, UITableViewDataSource {
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("myCell")

        cell?.textLabel?.text = "row #\(indexPath.row + 1)"

        return cell!
    }
}

输出正常。

好的,但是对于我拥有的任何tableView属性……我不希望它的委托设置为self吗?对于某些ViewController中的任意数量的TableView,是否有可能我希望将其委托设置为除self之外的其他对象?你能给你的第二个答案添加一些代码吗?@亲爱的,自我到底是什么?自我是取决于当前环境的东西。如果你问的是UIViewController,我会理解你的问题,但当你问的是self时,我不会理解。赛尔夫什么都不是。@Sulthan似乎我在混淆什么……从问题上看,赛尔夫指的是某个视图控制器,这不是很明显吗。或者在一般情况下,无论什么类符合protocolAkhi,那么通过这样做,您的代码变得更加模块化了吗?你没有将viewModel泄露给控制器吗?没有必要,对我来说,我认为让容器ViewController处理数据源/委派更自然、更可读。在某些情况下,做这样的事情可能会更好,但我不太确定:也许这会使您更容易将处理程序作为数据源进行测试,而不是将其作为viewController本身进行测试。你也可以在其他地方重复使用它,当你使用不同的架构模式(而不是常规的MVC)构建一个应用程序时,这可能会很有用,最终这取决于你,开发人员。给你一个小技巧:你可以创建一个扩展到你的ViewController和le
它不负责处理dataSource和Delegate方法。@AhmadF因此,如果我们遵循您的方法,我们也可以将Delegate和dataSource定义为不同的类。
import TaCoPopulator


class ViewControllerDataSource<TableOrCollectionView: PopulatorView> {
    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<MyViewPopulator>?

    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<Int, TextCollectionViewCell>(parentView: populatorView, provider: dp1, cellConfigurator: collectionViewCellConfig)
            let  section2factory = SectionCellsFactory<String, TextCollectionViewCell>(parentView: populatorView, provider: dp2, cellConfigurator: collectionViewCellConfig)
            self.populator = Populator(with: populatorView, sectionCellModelsFactories: [section1factory, section2factory])
        }

        if  let populatorView  = populatorView as? UITableView {
            let section1factory = SectionCellsFactory<Int, UITableViewCell>(parentView: populatorView, provider: dp1, cellConfigurator: tableViewViewCellConfig)
            let section2factory = SectionCellsFactory<String, UITableViewCell>(parentView: populatorView, provider: dp2, cellConfigurator: tableViewViewCellConfig)
            self.populator = Populator(with: populatorView, sectionCellModelsFactories: [section1factory, section2factory])
        }
    }

}
import UIKit

// ViewController File
class ViewController: UIViewController {
    var handler: Handler!

    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()

        handler = Handler()
        tableView.dataSource = handler
    }
}
import UIKit

class Handler:NSObject, UITableViewDataSource {
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("myCell")

        cell?.textLabel?.text = "row #\(indexPath.row + 1)"

        return cell!
    }
}