Перемещайте переменную AnyObject, используя или цепочку downcast (as) для доступа к свойствам различных классов. - PullRequest
0 голосов
/ 30 августа 2018

У меня есть два класса, в зависимости от того, в какую игру будет играть пользователь (код кода «пройден»). Я хочу использовать тот же контроллер представления, потому что вся логика похожа.

Так что в global я определил переменную questionAll : AnyObject. Затем на viewdidload() я присваиваю его либо Trivia() экземпляру, либо Diy() на основе значения passedTitle. Однако я могу получить доступ только к определенным свойствам этого экземпляра, используя downcasting, используя as? с if необязательной цепочкой.

Мне нужно использовать этот экземпляр и обращаться к свойствам во многих различных функциях, и потому я думал о том, чтобы сделать что-то вроде этого:

if let A = B as? Trivia || Diy { code here is same }

но очевидно, что это неправильно, и я не могу найти ответ в Интернете.

Ниже приведен соответствующий код:

var questionAll : AnyObject

override func viewDidLoad() {
    super.viewDidLoad()

    //based on the game title decide which game played
    if passedTitle == "Trivia" {
        questionAll = Trivia()
    }else if passedTitle == "Diy" {
        questionAll = Diy()
    }

    //calculate the total grades
    if let questionAllInstance = questionAll as? Trivia{
        for singlePoint in questionAllInstance.answers["level\(level)"]!{
            let sumGrade = singlePoint.reduce(0, {$0 + $1})
            totalGrade += sumGrade
        }
    }
    if let questionAllInstance = questionAll as? Diy{
        for singlePoint in questionAllInstance.answers["level\(level)"]!{
            let sumGrade = singlePoint.reduce(0, {$0 + $1})
            totalGrade += sumGrade
        }
    }
...

1 Ответ

0 голосов
/ 30 августа 2018

Использование AnyObject является запахом кода, обычно вы используете только ограниченный набор объектов для передачи вашему классу, и, глядя на код из вопроса, набор содержит только два типа: Trivia, и Diy. Так почему бы не поместить их обоих под один и тот же зонт?

protocol Question {
    var answers: [String:[Int]] { get } // or the actual dictionary type from your code
}

Затем вы можете просто объявить соответствие протокола для двух классов:

extension Trivia: Question {
    // nothing to do, Trivia should already have an answers property
}

extension Diy: Question {
    // nothing to do, Trivia should already have an answers property
}

, и используйте его в своем ВК:

var questionAll : Question?

override func viewDidLoad() {
    super.viewDidLoad()

    //based on the game title decide which game played
    if passedTitle == "Trivia" {
        questionAll = Trivia()
    }else if passedTitle == "Diy" {
        questionAll = Diy()
    }

    //calculate the total grades
    if let questionAllInstance = questionAll,
        let points = questionAllInstance.answers["level\(level)"] {
        for singlePoint in points { // I replaced the forced unwrap to the optional binding above
            let sumGrade = singlePoint.reduce(0, {$0 + $1})
            totalGrade += sumGrade
        }
    }

Теперь, если вы действительно заинтересованы в объявлении AnyObject или вынуждены использовать его по другим причинам, вы можете использовать switch, чтобы уменьшить дублирование в исходном коде:

override func viewDidLoad() {
    super.viewDidLoad()

    //based on the game title decide which game played
    if passedTitle == "Trivia" {
        questionAll = Trivia()
    }else if passedTitle == "Diy" {
        questionAll = Diy()
    }

    let answers: TypeOfAnswers? // an optional of what the `answers` property is
    switch questionAll {
    case let trivia as Trivia: answers = trivia.answers
    case let diy as Diy: answers = diy.answers
    default: answers = nil
    }

    if let points = answers?["level\(level)"] {
        for singlePoint in points {
            let sumGrade = singlePoint.reduce(0, {$0 + $1})
            totalGrade += sumGrade
        }
    }

В качестве альтернативы, вы можете использовать локальную функцию для обработки ответов:

override func viewDidLoad() {
    super.viewDidLoad()

    //based on the game title decide which game played
    if passedTitle == "Trivia" {
        questionAll = Trivia()
    }else if passedTitle == "Diy" {
        questionAll = Diy()
    }

    func process(answers: TypeOfAnswers) {
        if let points = questionAllInstance.answers["level\(level)"] {
            for singlePoint in points { // I replaced the forced unwrap to the optional binding above
                let sumGrade = singlePoint.reduce(0, {$0 + $1})
                totalGrade += sumGrade
            }
        }
    }

    switch questionAll {
    case let trivia as Trivia: process(answers: trivia.answers)
    case let diy as Diy: process(answers: diy.answers)
    default: break
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...