首页 > 解决方案 > 在协议中使用 self in function

问题描述

我有这个协议:

从 Storyboard 实例化 ViewController 的一种方法:

protocol Storyboarded {
    static func instantiate() -> Self
}

extension Storyboarded where Self: UIViewController {
    static func instantiate() -> Self {

        // this pulls out "MyApp.MyViewController"
        let fullName = NSStringFromClass(self)

        // this splits by the dot and uses everything after, giving "MyViewController"
        let className = fullName.components(separatedBy: ".")[1]

        // load our storyboard
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

        // instantiate a view controller with that identifier, and force cast as the type that was requested
        return storyboard.instantiateViewController(withIdentifier: className) as! Self
    }
}

一种将依赖项注入到 Viewcontrollers 中:

protocol DependencyInjection where Self: UIViewController {
    associatedtype myType: DependencyVC
    func injectDependencys(dependency: myType)
}

现在我想再添加一个,这样我就可以从 Dependency 本身创建 ViewController:

protocol DependencyVC {
    associatedtype myType: DependencyInjectionVC & Storyboarded
    func createVC() -> myType
}


extension DependencyVC {
    func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
        let viewController = T.instantiate()
        viewController.injectDependencys(dependency: self)
        return viewController
    }

}

但我自己得到这个错误:

无法使用类型为“(依赖项:Self)”的参数列表调用“injectDependencys”

这是我拥有的 DependencyClass:

class TopFlopDependency: DependencyVC {
    typealias myType = TopFlopVC


    var topFlopState: TopFlopState

    lazy var topFlopConfig: TopFlopConfig = {
        let SIBM = StatIntervalBaseModel(stat: "ppc", interval: "24h", base: "usd")
        return TopFlopConfig(group: Groups.large, base: "usd", valueOne: SIBM)
    }()

    init(state: TopFlopState) {
        self.topFlopState = state
    }

    func createVC() -> TopFlopVC {
        let topflopVC = TopFlopVC.instantiate()
        topflopVC.injectDependencys(dependency: self)

        let viewController: TopFlopVC = makeVC()

        return topflopVC
    }
}

使用 makeVC 时出现此错误:

“TopFlopDependency”要求类型“TopFlopDependency.myType”和“TopFlopDependency.myType”(又名“TopFlopVC”)等同于使用“makeVC”

其他解决方案:

protocol DependencyVC {   
}
extension DependencyVC {
    func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
        let viewController = T.instantiate()
        viewController.injectDependencys(dependency: self)
        return viewController
    }
}

尝试使用时:

let viewController: TopFlopVC = makeVC()

我得到无法推断 T 的错误。

为什么我不能这样做?你有一个解决方案我会如何让它工作?

谢谢!

标签: swiftgenericsprotocols

解决方案


当您调用时viewController.injectDependencys(dependency: self)self已知是 的某个子类型DependencyVC。但是,DependencyInjection'associatedtype myType: DependencyVC只是说符合 的类型DependencyInjection将使用某种类型 for myType(符合DependencyVC)。所以不能保证它的实际类型是myType.

associatedtypes 与泛型类型参数的工作方式不太一样,associatedtype因为在“定义”类型时给出了 s,而在“使用”类型时给出了泛型类型参数。

这一切都归结为这样一个事实,即您可能不想拥有 a associatedtype myType,而是DependencyVC直接采用 a 。

更新

根据您提供的其他信息,我相信这将是最好的解决方案:

protocol DependencyInjection where Self: UIViewController {
    func injectDependency(_ dependency: DependencyVC)
}

protocol DependencyVC {
    func makeVC<T: Storyboarded & DependencyInjection>() -> T
}

extension DependencyVC {
    func makeVC<T: Storyboarded & DependencyInjection>() -> T {
        let viewController = T.instantiate()
        viewController.injectDependency(self)
        return viewController
    }
}

正如您可能注意到的,我冒昧地重命名injectDependencys(dependency: DependencyVC)injectDependency(_ dependency: DependencyVC),因为您只注入了一个依赖项,而dependency:标签并没有真正在调用站点添加任何内容。

无论如何,这允许您使用您的依赖项创建视图控制器的实例。假设您将依赖项存储在名为 的变量中dependency,然后您可以通过以下方式从中创建视图控制器let topFlopVC: TopFlopVC = dependency.makeVC()


推荐阅读