Swift AnyObject 变量,使用 or 链接向下转换 (as) 来访问不同类的属性



我有两个类,取决于用户要玩的游戏(代码中的"passedTitle"(。我想使用相同的视图控制器,因为整个逻辑是相似的。

所以在全局我定义了一个变量questionAll : AnyObject。然后在viewdidload(),我根据passedTitle值将其分配给Trivia()实例或Diy()。但是,我只能通过使用带有可选链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
}
}
...

AnyObject的用法是一种代码异味,通常你只使用有限的一组对象传递给你的类,通过查看问题中的代码,该集合只包含两种类型:TriviaDiy。那么为什么不把它们放在同一个保护伞下呢?

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
}

,并在您的 VC 中使用它:

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
}

最新更新