Swift泛型类型的属性和方法

3

如何将通用类型存储在属性中,然后使用该类型属性传递给方法?

我有一个工厂,其方法接收视图控制器类型,但返回该视图控制器的实例(容器会处理此操作)。

public protocol ViewControllerFactoryProtocol {
    func getViewController<T: UIViewController>(type: T.Type) -> UIViewController
}

public class ViewControllerFactory: ViewControllerFactoryProtocol {

private let container: Container

public init(container: Container) {
    self.container = container
}

public func getViewController<T: UIViewController>(type: T.Type) -> UIViewController {
    return self.container.resolve(type)!
}

我带有以下这样的属性

而我拥有这样的属性

var destinationViewController: UIViewController.Type { get }

现在我想做的事情是类似于:
factory.getViewController(self.destinationViewController)

我在这里声明destinationViewControllerLoginViewController.self

但是它并不能像那样工作。奇怪的是,如果我直接这样做,它就能正常工作:

factory.getViewController(LoginViewController.self)

有需要帮助的吗?谢谢。

1
“但它不是这样工作的”:那它是怎么工作的?或者有什么错误信息? - 0x416e746f6e
它只是抛出了访问错误。 - zhuber
1
这就是为什么它会崩溃。你试图强制解包一个空值。调试一下为什么它返回了空值。显然它应该返回一些对象。 - 0x416e746f6e
那是Swinject容器,所以我无法进行太多的调试。但奇怪的是factory.getViewController(LoginViewController.self)可以工作,所以我的类型存储属性肯定有问题。 - zhuber
你怎么在该容器中注册类型? - 0x416e746f6e
显示剩余2条评论
1个回答

2

没有看到resolve的代码,所以无法确定它为何崩溃,但我有一个好主意。我怀疑你将泛型类型参数和运行时类型参数之间的区别弄混了。考虑这个简化的代码。

func printType<T>(type: T.Type) {
    print("T is \(T.self)")
    print("type is \(type)")
}

class Super {}
class Sub: Super {}

printType(Super.self) // Super/Super. Good.
printType(Sub.self)   // Sub/Sub. Good.

let type: Super.Type = Sub.self
printType(type) // Super/Sub !!!!!!

为什么最后一个案例是Super/Sub?因为printType<T>在编译时被解析。它只看定义:
func printType<T>(type: T.Type)
let type: Super.Type

printType(type)

为了使这个工作,我需要一个 T,使得 T.TypeSuper.Type 相同。好吧,那就是 Super。因此这样编译:
printType<Super>(type)

现在在运行时,我们看到type等于Sub.self,它是Super.type的一个子类型,所以没问题。我们将其传递给printType<Super>并获得您正在查看的响应。
因此,在resolve内部,您可能在某个地方使用了T,而实际上您想使用type,同时您正在尝试"解析"UIViewController,这可能返回nil。

我能在调用self.container.resolve(type)之前以某种方式获取我需要的确切类型吗?然后将其传递而不是"type"到resolve方法。 - zhuber
我不确定这是否有帮助,但这是Swinject容器中的resolve方法:https://github.com/Swinject/Swinject/blob/master/Swinject/Container.swift - zhuber
您正在传递类型。Swinject 不使用它。请查看第 133 行左右。serviceType 的运行时值未被使用。仅使用编译时类型。这需要在框架方面进行更改。可能无法以与 Swinject 想要实现的方式在 Swift 中执行此操作。该框架似乎非常复杂,我个人不建议使用它(它会交错 UIStoryboard,这总是稳定性不好的迹象)。但如果您确实想要使用它,您肯定需要对其精确的运作方式进行学习。 - Rob Napier
在下一个显而易见的问题之前再重申一遍:我不知道是否有任何对 Swinject 的小改变可以使其工作。我会向项目提出问题。 - Rob Napier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接