字符串

时间:2018-03-16 19:49:03

标签: json swift generics

编辑:(初始示例过于简化,因此我重写了更具体的代码)

基于http://holko.pl/2016/01/05/typed-table-view-controller/

我试图看看是否可以从字符串中设置类型的泛型参数..

说我们有这个代码

protocol Updatable
{
    associatedtype ViewModel
    func updateWith(viewModel: ViewModel)
}

class ToasterCell: UITableViewCell
{
    var toast: String?
    func updateWith(viewModel: String) {
        toast = viewModel
        //Additional config...
    }
}
extension ToasterCell: Updatable
{
    typealias ViewModel = String
}

class PriceCell: UITableViewCell
{
    var tagPrice: Float?
    func updateWith(viewModel: Float) {
        tagPrice = viewModel
        //Additional config
    }
}
extension PriceCell: Updatable
{
    typealias ViewModel = Float
}


protocol CellConfiguratorType {

    var reuseIdentifier: String { get }
    var cellClass: AnyClass { get }

    func updateCell(_ cell: UITableViewCell)
}

class MyTypeTest<Cell> where Cell: Updatable , Cell: UITableViewCell
{
    let viewModel: Cell.ViewModel
    let reuseIdentifier: String = String(describing: Cell.self)
    let cellClass: AnyClass = Cell.self
    init(viewModel: Cell.ViewModel) {
        self.viewModel = viewModel
    }
    func updateCell(_ cell: UITableViewCell)
    {
        if let c = cell as? Cell
        {
            c.updateWith(viewModel: viewModel)
        }
    }
}
extension MyTypeTest: CellConfiguratorType{
}

let myTT1 = MyTypeTest<PriceCell>(viewModel: 3.76)
let myTT2 = MyTypeTest<ToasterCell>(viewModel: "Carpe Diem")
let data = [myTT1, myTT2] as [CellConfiguratorType] // data for the tableView
//register Cell calss ...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cellConf = data[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: cellConf.reuseIdentifier)
    cellConf.updateCell(cell)
    return cell
}

我们希望这样做,以便从我们从JSON响应中获得的字符串设置类型T.

//Some JSON {"list":[{"k":"Price","v":368.0},"{"k":"ToasterCell","v":"YOLO"},"{"k":"Toaster","v":"Space"},{"k":"PriceCell","v":1999}]}

JSON值不直接映射到任何对象/类,所以我需要使用该键“k”来知道要使用的巫婆类。

我尝试使用“k”值中的字符串来设置单元格配置器。

(简短的例子)

//for now let skip any logic in decoding the value / viewModel.
let myTT1 = MyTypeTest<NSClassFromString(list.first.k + "Cell")>(viewModel: list.first.v as Any)

我得到的只是错误:

  • 无法指定类型'T'的值来输入'AnyClass'(又名'AnyObject.Type')
  • 使用未声明类型'myTypeOBJ'

有没有办法通过字符串来实现这一点,或者我是否真的需要为我从JSON响应中获得的任何类型创建一个巨大的“if-else”结构?

编辑: 我尝试使用Cell类型的参数向CellConfigurator添加一个init,这样它就可以从它自己的参数中推断出Type。

init(viewModel: Cell.ViewModel, inferUsing: Cell){....}

我可以尝试使用它(但是因为PAT阻碍了,所以不起作用)

func getSafeBundelName() -> String
    {
        if let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String
        {
            return namespace
        }
        return ""
    }

let cellClass = NSClassFromString("\(getSafeBundelName()).PriceCell") as? UITableViewCell.Type
let cell = cellClass?.init()
let myTT1 = MyTypeTest(viewModel: list.first.v as Any, inferUsing: cell)

我得到的错误是不能感染细胞类型。如果我尝试在&lt;&gt;中使用cellClass
例如:MyTypeTest<cellType>(viewModel: 3.76)所有它给我的是“cellClass”没有声明。在我看来,我正在走向死胡同,在这种情况下,PAT无法以任何我能看到的方式推断出来。我发现这种限制非常令人难过。

1 个答案:

答案 0 :(得分:1)

如果将结果从NSClassFromString向下转换为可以调用已知初始化程序的类型,则可以执行此操作。如果它总是Toaster或子类,那么你可以这样做:

if let myTypeOBJ = NSClassFromString("Toaster") as? Toaster.Type {
    let test = myTypeTest(someOBJ: myTypeOBJ.init())
    // test.someThing will be of type Toaster
}

为了使NSClassFromString起作用,您还需要指定您希望如何在objc中表示类型名称,否则将在类型名称前面添加一些其他内容:

@objc(Toaster)
class Toaster: NSObject