我在使用Swift Dictionaries存储通用对象时遇到了困难。
我试图以下列方式存储对象:
[C: Container<C>], where C: ContentType
这样字典的结构如下:
Key Value
--- -----
A Container<A>
B Container<B>
...
我有一个名为“ContentType”的类,它存储有关内容类型的元数据(即名称,大小,重量等)。
class ContentType: NSObject { ... }
我有许多不同的“ContentType”子类,每个子类描述一种特定类型的内容。
class ContentTypeA: ContentType { ... }
class ContentTypeB: ContentType { ... }
我还有一个名为“Container”的类,用于存储与内容类型相关的信息。恰当地,它是一个泛型类,它的泛型类型为“ContentType”。
class Container<C: ContentType>: NSObject { }
我还在“Container”上实现了扩展,为特定的“ContentType”定义了函数。
extension Container where C: ContentTypeA {
func fancyFunctionOnlyFoundInContentTypeA() { }
}
extension Container where C: ContentTypeB {
func fancyFunctionOnlyFoundInContentTypeB() { }
}
在我的主控制器类中,我实现了以下下标overloader。
subscript<C: ContentType>(contentType: C) -> Container<C> {
// If Container for ContentType "C" does not exist
if (self.containers[contentType] == nil) {
// Then create it
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
}
// And return it
return self.containers[contentType]! as! Container<C>
}
这个想法是你可以获得/重用一个特定“ContentType”的“容器”,它将被准备好。
// Define a ContentType singletons somewhere
static let ContentTypeASingleton = ContentTypeA.init()
static let ContentTypeBSingleton = ContentTypeA.init()
...
// Using the subscript, the Container for ContentTypeA/ContentTypeB can be obtained
let containerForTypeA = self[ContentTypeASingleton]
let containerForTypeB = self[ContentTypeBSingleton]
从这里开始,可以调用特定于每个ContentType的Container扩展。
containerForTypeA.fancyFunctionOnlyFoundInContentTypeA()
containerForTypeB.fancyFunctionOnlyFoundInContentTypeB()
我相信所有这一切都应该在理论上起作用,它肯定会在Swift 4,Xcode 9.0中编译。但是,在执行以下操作时:
// Then create it
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
我收到以下错误:
Could not cast value of type 'Test.Container<Test.ContentTypeA>' (0x109824a00) to 'Test.Container<Test.ContentType>' (0x109824638).
由于ContentTypeA继承自ContentType,我不明白为什么这是一个问题。似乎Swift Dictionaries无法存储ContentType&lt;类型的对象。 AnySubclassOfContentType&gt; ,并且必须将对象存储为ContentType&lt; ContentType&gt;
有没有人有任何建议?欢呼声。
class ViewController: UIViewController {
var containers = [ContentType : Container<ContentType>]()
override func viewDidLoad() {
super.viewDidLoad()
let contentTypeA = ContentTypeA.init()
let contentTypeB = ContentTypeB.init()
let containerForTypeA = self[contentTypeA]
let containerForTypeB = self[contentTypeB]
containerForTypeA.fancyFunctionOnlyFoundInContentTypeA()
containerForTypeB.fancyFunctionOnlyFoundInContentTypeB()
}
subscript<C: ContentType>(contentType: C) -> Container<C> {
if (self.containers[contentType] == nil) {
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
}
return self.containers[contentType]! as! Container<C>
}
}
class ContentType: NSObject { }
class Container<C: ContentType>: NSObject { }
class ContentTypeA: ContentType { }
class ContentTypeB: ContentType { }
extension Container where C: ContentTypeA {
func fancyFunctionOnlyFoundInContentTypeA() { }
}
extension Container where C: ContentTypeB {
func fancyFunctionOnlyFoundInContentTypeB() { }
}
答案 0 :(得分:3)
崩溃发生是因为Swift泛型是不变的,因此Container<B>
不是Container<A>
的子类,即使B
是A
的子类,也不是任何向下的将失败,强迫演员导致崩溃。
您可以使用AnyObject
作为字典中的基类来解决此问题,因为Container
来自NSObject
:
var containers = [ContentType : AnyObject]()
subscript<C: ContentType>(contentType: C) -> Container<C> {
if let container = containers[contentType] {
return container as! Container<C>
} else {
let container = Container<C>()
containers[contentType] = container
return container
}
}