我想有一个不同的页面数组(HTML和PDF页面,以后可能会添加更多)。
我认为这是一个练习使用协议编程的好机会。
这就是我想到的:
protocol PageDataProtocol {
var data: String? {get}
}
protocol PageTitleProtocol {
var title: String {get}
var pageType: Page {get}
}
struct PDFData: PageTitleProtocol {
var title: String
var pageType: Page
}
struct HTMLData: PageDataProtocol, PageTitleProtocol {
var title: String
var data: String?
var pageType: Page
}
enum Page {
case html
case pdf
case links
}
var pageArray : [PageTitleProtocol]? = []
let test = PDFData(title: "title1", pageType: .html)
pageArray?.append(test)
let testtwo = HTMLData(title: "title2", data: "hello", pageType: .pdf)
pageArray?.append(testtwo)
for page in pageArray! {
print (page.title)
if let pg = page as? HTMLData {
print (pg.data)
}
if page.pageType == .pdf {
print ( (page as? HTMLData)?.data )
}
}
一切似乎都很好,但在我的书面声明中,有一个明显的问题。
编辑:我不认为上面的代码是完美的。但是对于下面的问题,pagerarray是可选的,因为在从API下载之前,可能没有页面,但这与从API中提取的页面不同。
存储枚举是没有意义的,因为无论如何我都必须转换为正确的类型。
这样做的想法是,我可以将页面存储在单个数组中,根据需要获取它们,然后显示在视图控制器(由视图模型格式化)中,而不是从2+数组中绘制不同类型的页面。
我想写一个很好的case语句来正确地显示信息(在我完成的结构中会有其他字段),但是这在我的实现中似乎是不可能的。
如何重构代码以便能够打开上面声明的页面类型?
最佳答案
如果您的页面数据是预先定义的,并且从头密封的,那么您甚至根本不需要一个protocol
(它甚至会起反作用),只需扩展您的enum
:
enum Page {
case html(title: String, data: String?)
case pdf(title: String)
case links(title: String, array: [URL]) // or something else, it wasn't used in the example
var title: String {
switch(self) {
case .html(let title, _), .pdf(let title), .links(let title, _):
return title
}
}
}
var pageArray : [Page] = [] // no need to make it optional, btw
let test = Page.pdf(title: "title1")
pageArray.append(test)
let testtwo = Page.html(title: "title2", data: "hello")
pageArray.append(testtwo)
for page in pageArray {
print (page.title)
if case .html(_, let data) = page {
print(data)
}
}