Making a TableViewDataSource more independent of the data it utilizes I have written an ordinary tableView to display a list of players, with the following data structure that's in place. 


A Conductor (which is the user), has many
Orchestra? objects.
A Orchestra? has many Player? objects


All objects besides the Conductor are cast as Optional, meaning that a Conductor could have no Orchestra, and an Orchestra could have no player.

The Conductor is a singleton object. At anytime the currentConductor could be called (similar to how you could always call currentUser in Parse or Firebase)

Currently, I am displaying all the players for a Conductor's currentOrchestra object. My concern is that my TableViewDataSource is too tightly coupled with having to know about how my Conductor class functions, and I could like to decouple some of the logic.

For instance:

class OrchestraViewDataSource: NSObject, UITableViewDataSource {

    var isCurrentOrchestraAvaliable = false

    override init() {
        super.init()

        if let _ = User.shared.currentOrchestra {
            isCurrentOrchestraAvaliable = true
        }
    }

    func numberOfSections(in tableView: UITableView) -&gt; Int {

        if isCurrentOrchestraAvaliable {
            return 2 //Shows Performers and Non-performers
        }

        return 0
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {

        if section == 0 {
            return User.shared.currentOrchestra?.performers.count ?? 0
        } else {
            return User.shared.currentOrchestra?.nonPerformers.count ?? 0
        }

    }

    //... Additional code omitted
}


At the moment, I call User.shared.currentOrchestra?.performers.count because the user could change the line up of the performers and non-performers. Is calling the Singleton to populate my data source ok? And if not, what are better ways to make my TableViewDataSource more independent?

Thanks!
My concern is that my TableViewDataSource is too tightly coupled with having to know about how my Conductor class functions, and I could like to decouple some of the logic.


Create a protocol which defines the data in the form that the data source needs. This will separate the requirements of the data from the implementation of the class providing the data, which would give you flexibility to change the behaviour of the Orchestra object without also having to change the data source. 

The orchestra object should implement the protocol and provide the data in the required format. You can use a class extension on the orchestra or conductor to add the required code.


  Is calling the Singleton to populate my data source ok? And if not, what are better ways to make my TableViewDataSource more independent? 


Using Singletons often leads to problems. It would be better to follow the dependency inversion principle and pass an instance of the conductor to the data source. From the code you have shown you only seem to be using the orchestra, and so the conductor itself is not needed.

Example

The example below shows how to:


Define a protocol.
Use a class extension to have a class conform to the protocol.
Update the data source to use the protocol instead of the concrete class.
Pass the orchestra instance into the data source.


1. Define a protocol:

protocol Performers {
    var numberOfSections: Int {
        get
    }
    func numberOfPerformers(inSection: Int) -&gt; Int
    func performer(atIndex: Int, inSection: Int) -&gt; Performer
}


2. Add a class extension on Orchestra to conform to the Performers protocol:

extension Orchestra: Performers {
    var numberOfSections: Int {
        return 2
    }

    func numberOfPerformers(inSection section: Int) -&gt; Int {
        if section == 0 {
            return performers.count ?? 0
        } else {
            return nonPerformers.count ?? 0
        }
    }

    func performer(atIndex index: Int, inSection section: Int) -&gt; Performer {
        if section == 0 {
            return performers[index]
        } else {
            return nonPerformers[index]
        }
    }
}


3. Modify the data source to use the protocol

class OrchestraViewDataSource: NSObject, UITableViewDataSource {

    var performers: Performers?

    override init(performers: Performers?) {
        super.init()
        self.performers = performers
    }

    func numberOfSections(in tableView: UITableView) -&gt; Int {
        return performers?.numberOfSections ?? 0
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
        return performers?.numberOfPerformers(inSection: section) ?? 0
    }

    //... Additional code omitted
}


4. Pass the orchestra instance to the data source

let currentOrchestra = User.shared.currentOrchestra
let dataSource = OrchestraViewDataSource(performers: orchestra)