2
\$\begingroup\$

I have a UITableViewController that displays a list of lift names (think weightlifting) and it's used for two different things. It can be accessed from view A to select a lift that will be saved as a user default. It can also be accessed from view B to select a lift that will then filter a list of lift events. In each case, I want a checkmark on the appropriate cell to indicate the current default lift (if coming from view A) and a checkmark on the appropriate cell to indicate the currently selected filter (if coming from view B).

I created a view model for the table cells:

struct LiftCellViewModel: SelectionsRepresentable {

    let liftName: String!
    let liftsDictionary: [String: String]!

    var text: String {
        return liftName
    }

    var accessoryType: UITableViewCellAccessoryType {
        let defaultLiftUuid = UserDefaults.lift()
        let defaultLiftName = liftsDictionary[defaultLiftUuid]

        if liftName == defaultLiftName {
            return .checkmark
        } else {
            return .none
        }
    }
}

This works very, but only handles one of the scenarios (coming from view A). So, to try and get it to also work with the other scenario (coming from view B) I'm passing in a bool if the list is being used to select a filter and using that in a switch statement to determine what path to take in order to set the checkmark:

let liftName: String!
let liftsDictionary: [String: String]!
let selectForFilter: Bool!

var text: String {
    return liftName
}

var accessoryType: UITableViewCellAccessoryType {

    switch selectForFilter {
    case true:
        let filterLiftUuid = UserDefaults.logFilterLiftUuid()
        let filterLiftName = liftsDictionary[filterLiftUuid!]

        if liftName == filterLiftName {
            return .checkmark
            } else {
            return .none
            }
    case false:
        let defaultLiftUuid = UserDefaults.lift()
        let defaultLiftName = liftsDictionary[defaultLiftUuid]

        if liftName == defaultLiftName {
            return .checkmark
        } else {
            return .none
        }
    default:
        return .none
    }
}

This view is used to create each cell in didSelectRow:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellViewModel: SelectionsRepresentable
    let cell = tableView.dequeueReusableCell(withIdentifier: "liftCell", for: indexPath)
    let lift = viewModel.fetchedResultsController?.object(at: indexPath) as! Lift
    let liftName = lift.liftName

    cellViewModel = LiftCellViewModel(liftName: liftName, liftsDictionary: liftsDictionary, selectForFilter: selectForFilter)

    cell.textLabel?.text = cellViewModel.text
    cell.accessoryType = cellViewModel.accessoryType

    return cell
}

This works but the switch statement seems like a lot of code to do something so simple. Is there a Swiftier way to do this?

\$\endgroup\$
  • \$\begingroup\$ A switch for a Bool type?? \$\endgroup\$ – πάντα ῥεῖ May 12 '17 at 16:24
  • \$\begingroup\$ I'm asking for help. What do you suggest? \$\endgroup\$ – Jim May 12 '17 at 16:25
1
\$\begingroup\$

1 You can clean switch as:

var accessoryType: UITableViewCellAccessoryType {
    if selectForFilter && liftsDictionary[UserDefaults.logFilterLiftUuid()!] != nil {
        return .checkmark
    }
    if liftsDictionary[UserDefaults.lift()] != nil {
        return .checkmark
    }
    return .none
}

2 From your code, I can assume that SelectionsRepresentable is like:

protocol SelectionsRepresentable {
    var text: String { get }
    var accessoryType: UITableViewCellAccessoryType { get }
}

Here, as name suggest, this protocol is only related to cell selection.
It has nothing to do with text.
Try to remove that variable from protocol.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.