公共协议BasicSwiftClassLayout {
var nibName:String {get}
}
我的班级是这样的:
public class BasicSwiftClass< Layout:BasicSwiftClassLayout> {}
我已经定义了2个不同的结构,以便我可以用2个不同的笔尖启动这个类:
public struct NormalLayout:BasicSwiftClassLayout {
public let nibName =“NormalLayoutNibName”
}
和
public struct OtherLayout:BasicSwiftClassLayout {
public let nibName =“OtherLayoutNibName
}
我现在有2个问题基于此.
>我想使用Layout变量来检索此类启动的nib名称.因此,如果我要将此类创建为:let myView = BasicSwiftClass< NormalLayout>我希望能够在类中检索NormalLayout的nibName(“NormalLayoutNibName”).我想做一些像myNib = Layout.nibName这样的事情,但它只是告诉我实例成员nibName不能用于类型Layout那么我该如何去检索nibName呢?
>当我没有将泛型类添加到我的类中并且它只是公共类BasicSwiftClass时,classForCoder只是MyProject.BasicSwiftClass.现在我已经添加了通用行为,classForCoder将作为MyProject.BasicSwiftClass< Layout.NormalLayout>返回.调用let bundle = Bundle(for:classForCoder)时不再返回正确的bundle我是否需要覆盖classForCoder变量?或者我在这里做错了什么?
谢谢!
由于您的BasicSwiftClass没有符合BasicSwiftClassLayout类型的实例,而只是了解类型本身,因此您应该将nibName要求设置为static,因此可以在类型本身上调用它,而不是实例,像这样:public protocol BasicSwiftClassLayout { static var nibName: String { get } } public struct NormalLayout: BasicSwiftClassLayout { public static let nibName = "NormalLayoutNibName" } public struct OtherLayout: BasicSwiftClassLayout { public static let nibName = "OtherLayoutNibName" }
至于你的第二个问题,我不认为Bundle(对于类:AnyClass)初始化程序适用于泛型类,句点.如果有人找到了解决方法的话,我很高兴出错,但我的猜测是,因为编译器会生成泛型类型的具体变体,而且只有实际使用的那些,这会带来一些挑战:
>可以在任何导入模块中使用/生成泛型类型的特定特化,并且可以查看和访问您的泛型类型.例如,如果一个不同的模块导入了你的代码并定义了一个公共结构的DifferentLayout:BasicSwiftClassLayout类型,那么变异BasicSwiftClass< DifferentLayout>是你的bundle的一部分,它定义了BasicSwiftClass的所有逻辑,但在编译时没有那个变化,或者是另一个模块,它导致编译器创建了这个特化?
>您没有在技术上定义专门类型BasicSwiftClass< OtherLayout>,编译器基于确定它将在何处使用.所以再次,它可以模糊这个真正属于哪个捆绑.
我猜测如果有一种方法可以引用泛型类型本身,即一个非专业化的BasicSwiftClass< Layout>类型引用,然后Bundle(for :)将正常工作.但是没有办法像这样引用泛型类型,因为它更像是编译器用于生成具体特化的模板,而不是运行时存在的实际类型.
建议的替代方法:
如果使协议需要类型的一致性,则可以获取布局的包而不是BasicSwiftClass.例如.:
public protocol BasicSwiftClassLayout: class { static var nibName: String { get } } final public class NormalLayout: BasicSwiftClassLayout { public static let nibName = "NormalLayoutNibName" } public class BasicSwiftClass<Layout: BasicSwiftClassLayout> { func loadFromNib() { let view = Bundle(for: Layout.self).loadNibNamed(Layout.nibName, owner: self, options: nil)?.first } }
创建泛型类型的数组
回答您关于如何创建BasicSwiftClass数组的问题< Layout>对于Layout的不同值,有不同的方法可以根据您需要如何使用从数组中检索的元素来解决此问题.最终,Swift要求集合(包括数组)包含所有相同类型的元素,或者可以作为相同的常见类型进行寻址,因此所有不同的方法都基于转换,包装或转换每个BasicSwiftClass< Layout>.实例到一些公共类型,它公开了你想在每个实例上调用的常用功能.
最简单的解决方案可能是创建一个BasicSwiftClass< Layout>的协议.符合,暴露您需要的功能.例如,如果您关心的是从每个实例获取视图以添加到视图层次结构,您可以执行以下操作:
public protocol ViewRepresentable { var view: UIView { get } } extension BasicSwiftClass<Layout>: ViewRepresentable { public var view: UIView { // load the nib, connect outlets and do other setup, then return the appropriate UIView } } let array: [ViewRepresentable] = [BasicSwiftClass<IPadLayout>, BasicSwiftClass<NormalLayout>] array.forEach { self.containerView.addSubview($0.view) }
如果您需要更专业的东西或在内部保留某些类型信息等,您可能需要使用包装器或类型橡皮擦.您也可以尝试使用BasicSwiftClass< Layout>继承自具有您需要的基本功能的非泛型超类,并将该集合键入为该超类类型的实例数组.但是,如果您可以在非通用协议中表达共同要求,那么这应该让您保持最简单的路径.