简体   繁体   English

Swift:将子类型的对象分配给带有泛型的基类类型的变量会产生错误

[英]Swift: Assigning an object of type sub class to a variable of type base class with generics produces error

I want to assign a sub class ( TapWhatYouHearViewController ), that inherits from its parent class ( BaseLectureViewController ) with implementing the generic using an inherited type ( TapWhatYouHear ), to a variable of type parent class ( BaseLectureViewController ) with the generic of type base class ( Game ). 我想分配一个子类TapWhatYouHearViewController ),它继承自其父类BaseLectureViewController ),使用继承类型TapWhatYouHear )实现泛型,使用类型基类的泛型类型的父类BaseLectureViewController )类型的变量( 游戏 )。

Swift procudes the following error: Swift会产生以下错误:

Swift:: Error: cannot assign value of type 'TapWhatYouHearViewController' to type 'BaseLectureViewController?' Swift :: Error:无法指定类型'TapWhatYouHearViewController'的值来键入'BaseLectureViewController?'

I've read, that one solution eg in Java would be using a wildcard generic, but this is not possible in Swift. 我已经读过,例如Java中的一个解决方案将使用通配符泛型,但这在Swift中是不可能的。 Is there any other solution? 还有其他解决方案吗?


This is my setup: 这是我的设置:

/** GAME TYPES **/

enum GameType {
    case TapWhatYouHear,
    case ChooseTranslation
}

class Game {
    var title: String?
    var type: GameType?
}

class TapWhatYouHear : Game {
    var audio: String?
    var type: GameType = GameType.TapWhatYouHear
}

class ChooseTranslation : Game {
    var video: String?
    var type: GameType = GameType.ChooseTranslation
}

/** VIEW CONTROLLERS **/

class BaseLectureViewController<T: Game> {
   var game: T?
}

class TapWhatYouHearViewController : BaseLectureViewController<TapWhatYouHear> {

}

class ChooseTranslationViewController : BaseLectureViewController<ChooseTranslation> {

}

I want to do the following: 我想做以下事情:

var game: Game = TapWhatYouHear() // <-- Depending on the user interaction, this can be any sub class of "Game"
var viewController: BaseLectureViewController<Game>

switch game.type {
    case .ChooseTranslation:
        viewController = TapWhatYouHearViewController() // <--Swift:: Error: cannot assign value of type 'TapWhatYouHearViewController' to type 'BaseLectureViewController<Game>?'
    case .TapWhatYouHear:
        viewController = ChooseTranslationViewController()
}

viewController.game = TapWhatYouHear()

What I'm trying to do is determine at runtime which sub class of BaseLectureViewController should be assigned to the viewController variable. 我要做的是在运行时确定应该将哪个BaseLectureViewController子类分配给viewController变量。 To save code, I then want to assign a game of type Game to the game property of the BaseLectureViewController . 为了保存代码,我想要将Game类型的Game分配给BaseLectureViewControllergame属性。

The generic approach you have in mind is not possible. 您想到的通用方法是不可能的。 My suggestion is to go with a simple inheritance solution where you override getGame() in your concrete ViewController (ie TapWhatYouHearViewController ) and cast the game to your specific type. 我的建议是使用一个简单的继承解决方案,你在具体的ViewController中重写getGame() (即TapWhatYouHearViewController )并将游戏转换为你的特定类型。

import UIKit

enum GameType {
    case TapWhatYouHear
    case ChooseTranslation
}

class Game {
    var title: String?
    var type: GameType?
}

class TapWhatYouHear : Game {
    var audio: String?

    override init() {
        super.init()
        type = GameType.TapWhatYouHear
    }
}

class ChooseTranslation : Game {
    var video: String?

    override init() {
        super.init()
        type = GameType.ChooseTranslation
    }
}


/** VIEW CONTROLLERS **/



protocol Lecture {
    var game: Game? { get set }
}

class BaseLectureViewController: UIViewController, Lecture {

    var game: Game?
    func getGame() -> Game? {
        fatalError("Must be implemented in subclass")
    }
}

class TapWhatYouHearViewController : BaseLectureViewController {
    override func getGame() -> TapWhatYouHear? {
        return game as? TapWhatYouHear
    }
}

class ChooseTranslationViewController : BaseLectureViewController {
    override func getGame() -> ChooseTranslation? {
        return game as? ChooseTranslation
    }
}

var game: Game = TapWhatYouHear() // <-- Depending on the user interaction, this can be any sub class of "Game"
var viewController: BaseLectureViewController?

if let gameType = game.type {
    switch gameType {
    case GameType.ChooseTranslation:
        viewController = TapWhatYouHearViewController() // <--Swift:: Error: cannot assign value of type 'TapWhatYouHearViewController' to type 'BaseLectureViewController<Game>?'
    case GameType.TapWhatYouHear:
        viewController = ChooseTranslationViewController()
    }

    viewController?.game = TapWhatYouHear()
}



Change the variable declaration to 将变量声明更改为

var viewController: BaseLectureViewController<TapWhatYouHear>

Or skip generics and declare your super class as 或者跳过泛型并将你的超级类声明为

class BaseLectureViewController {
    var game: Game?
}

If all you want to do is to assign a game property with an instance of specific subclass of Game , then you might use something like this, omitting generics 如果您要做的就是为game属性分配一个特定的Game子类实例,那么您可以使用类似的东西,省略泛型

class Game {
    var title: String?

    required init() {}
}

class TapWhatYouHear : Game {
    var audio: String?
}

class ChooseTranslation : Game {
    var video: String?
}

/** VIEW CONTROLLERS **/

class BaseLectureViewController : UIViewController {
    var game: Game

    init(gameType: Game.Type)
    {
        game = gameType.init()
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class TapWhatYouHearViewController : BaseLectureViewController{
    init()
    {
        super.init(gameType: TapWhatYouHear.self)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class ChooseTranslationViewController : BaseLectureViewController{
    init()
    {
        super.init(gameType: ChooseTranslation.self)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

usage 用法

var viewController : BaseLectureViewController
viewController = TapWhatYouHearViewController()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM