我想有一个不同的页面数组(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)
    }
}

09-17 05:21