Swift 2到3转换错误,类型为'[Any]'的值没有成员

时间:2017-05-17 23:19:09

标签: swift3

我遇到了Swift 2到3转换工作的问题以及一些遗留语法给出:类型'[Any]'的值没有成员错误。

我希望有人能指出我一个好的解决方案。

Swift 2代码

Swift 2 code

func search() {

    epsonPrinters = [Printer]()
    starPrinters = [Printer]()

    epson_startSearching()

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { [unowned self] in

        let devices = SMPort.searchPrinter()

        self.starPrinters = devices.map { portInfo -> Printer in

            let p = Printer(
                id: portInfo.modelName,
                make: "Star Micronics",
                model: portInfo.modelName,
                portName: portInfo.portName)

            if let name = portInfo.modelName as? String {
                p.emulation = name.containsString("TSP143") ? "StarGraphics" : "StarLine"
            }

            return p
        }
    }
}

Swift 3 Code (我在有错误的区域上添加了评论)

    func search() {

    epsonPrinters = [Printer]()
    starPrinters = [Printer]()

    epson_startSearching()

    DispatchQueue.global(qos: .background).async { [unowned self] in

        let devices = SMPort.searchPrinter()

        self.starPrinters = [devices.map { portInfo -> Printer in

        // id, model and portName in below fails with messages like:
        // Value of type '[Any]' has no member 'modelName'
            let p = Printer(
                id: portInfo.modelName,
                make: "Star Micronics",
                model: portInfo.modelName,
                portName: portInfo.portName)

            // error on portInfo.modelName
            // Value of type '[Any]' has no member 'modelName'
            if let name = portInfo.modelName as? String {
                p.emulation = name.containsString("TSP143") ? "StarGraphics" : "StarLine"
            }

            return p
            }!]
    }
}

我知道我可以用以下内容替换'id:...'部分:

id: ((portInfo[0] as AnyObject).modelName) ?? "",

但这不正确,因为根据我们找到的打印机数量,PortInfo可以没有,1或倍数。

我很感激任何以优雅的方式重构这一点的建议,这是一个很好的Swift 3语法,可能会存在于Swift 4中。

我正在使用Xcode 8.3.2

1 个答案:

答案 0 :(得分:0)

当您收到有关类型的错误时,您最好检查每个变量的类型。当您在devices行中选择let devices = ...时,Xcode的快速帮助会显示如下内容:

声明 let devices: [Any]?

首先,它是一个可选项,您需要在使用实际内容之前将其解包。

其次,devices中的元素类型为Any,您无法应用任何方法(包括属性访问器)。您需要在适当的位置将其强制转换为适当的类型。

要解决上述两件事,你可以这样写:

guard let devices = SMPort.searchPrinter() as? [PortInfo] else {
    fatalError("This may never happen")
}

使用上面的警告声明,快速帮助将显示:

声明 let devices: [PortInfo]

非{可选,简单的PortInfo数组,因此您可以使用PortInfo的任何方法来处理此devices的元素。

我会将你的Swift 2代码翻译成Swift 3,如下所示:

func search() {

    epsonPrinters = []
    starPrinters = []

    epson_startSearching()

    DispatchQueue.global(qos: .default).async {
        guard let devices = SMPort.searchPrinter() as? [PortInfo] else {
            fatalError("This may never happen")
        }

        self.starPrinters = devices.map { portInfo -> Printer in

            let p = Printer(
                id: portInfo.modelName,
                make: "Star Micronics",
                model: portInfo.modelName,
                portName: portInfo.portName)

            if let name = portInfo.modelName {
                p.emulation = name.contains("TSP143") ? "StarGraphics" : "StarLine"
            }

            return p
        }
    }
}

您可能需要一些修复(我相信并不多)才能使用此代码,因为您没有显示所有相关内容,例如Printer的定义。