使用 swinject 注册具有关联类型的协议时出现问题 编辑

问题描述

我想开发一个使用核心数据和领域的存储库模式的应用程序。我想根据我的需要解决协议。目的是在程序集中注入一个通用的核心数据存储库/领域存储库协议。

此行出现问题 forEach

let happy_score = 5
let food_counter = 5
let debounce_jim = 0
let debounce = 0 
function jim(expression: string = "meh"){
    basic.clearScreen()
    debounce = 1
    console.log("jim")
    input.onButtonpressed(Button.A,function(){
        if (food_counter > 0){
            food_counter -= 1
            happy_score += 1
        }

    })

    while (debounce_jim == 0){
        input.onButtonpressed(Button.AB,function () {
            debounce = 0
            debounce_jim = 1
            snake()
        })
        pause(0)
        happy_score -= 1
        if (food_counter < 1){
            basic.showNumber(0)
        }
        if (food_counter < 0){
            food_counter = 0
        }
        if (happy_score > 2) {
            expression = "happy"
        }else if(happy_score <= 2 && happy_score >0){
            expression = "meh"
        } else {
            expression = "sad"
        }
    

        if (expression == "happy"){
            basic.showLeds(`
            . # . # .
            . # . # .
            . . # . .
            # . . . #
            . # # # .
            `)
        }
        if (expression == "meh"){
            basic.showLeds(`
            . # . # .
            . # . # .
            . . . . .
            # # # # #
            . . . . .
            `)
        }
        if (expression == "sad"){
            basic.showLeds(`
            . # . # .
            . . . . .
            . # # # .
            # . . . #
            . . . . .
            `)
        }
    }

}

function snake() {
    let player = game.createSprite(2,2)
    let food = game.createSprite(1,1)
    let score = 0
    food.setBlink(100)
    console.log("snake")
    while (debounce == 0){
        if (player.isTouchingEdge()){
            debounce = 1 
            debounce_jim = 0
            console.log("debounce")
            player.off()
            food.off()
            game_end(score)
        }
        
        if (player.isTouching(food)){
            score += 1
            food_counter += 1
            food.setX(randint(1,3))
            food.setY(randint(1,3))
        }
            
        pause(1000)
        player.move(1)
    input.onButtonpressed(Button.A,function(){
        player.changeDirectionBy(90)
    })
    input.onButtonpressed(Button.B,function () {
        player.changeDirectionBy(-90)
    })

    }}

function game_end(score: number){
    basic.showNumber(score)
    console.log("game end")
    pause(100)
    basic.showString("||")
    jim(null)

}

jim(null)

由于使用通用(关联类型)属性,我无法注入睡眠存储库协议。我该如何解决这个问题?

另外,非常感谢您的回复。它真的帮了我很多。我还有一个问题。

var 存储库:SleepRepositoryProtocol

Protocol 'SleepRepositoryProtocol' can only be used as a generic constraint because it has Self or associated type requirements

这给了我错误“Protocol 'SleepRepositoryProtocol' 只能用作通用约束,因为它具有 Self 或相关的类型要求”,我不知道如何解决我的 SleepRepositoryProtocol。

解决方法

这个错误很经典:

    container.register(SleepRepositoryProtocol.self) { r in

被禁止,因为 SleepRepositoryProtocolProtocol with Associated Type

您需要的是 assemble(container:) 方法是通用的并以这种方式声明,例如:

func assemble<Repository: SleepRepositoryProtocol>(container: Container,ofType type:Repository) {

但由于它是 Swinject's Assembly Protocol 的一部分,所以它不是一个选项,您需要找到另一个位置来放置 Generic Type Constraint

在您的情况下,它可以是封闭类型,例如:

class MyClass<Repository: SleepRepositoryProtocol>: Assembly {
    func assemble(container: Container) {
        container.register(Repository.self) { r in
          CoreDataSleepRepository(persistentContainer:r.resolve(NSPersistentContainer.self)!)
        }
        .inObjectScope(.container)
    }
}

编辑

你不能只写:

var repository: SleepRepositoryProtocol

一旦你在你的协议中添加了 associatedtype 你就可以永远把它当作一个普通的类型,只是作为一个 Generic Type Constraint

因此,如果我使用您的其他属性更新 MyClass

class MyClass<Repository: SleepRepositoryProtocol>: Assembly {
    var repository: Repository

    var items: [SleepEntity]?

    private let assembler: Assembler

    init(assembler: Assembler) {
        self.assembler = assembler
        
        repository = assembler.resolver.resolve(Repository.self)!
    }

    func assemble(container: Container) {
        container.register(Repository.self) { r in
          CoreDataSleepRepository(persistentContainer:r.resolve(NSPersistentContainer.self)!)
        }
        .inObjectScope(.container)
    }
}