转换为字符串Any值

时间:2018-07-23 01:32:26

标签: swift

此操作失败(无法扩展非标称类型“任何”)

extension Any {
    func literal() -> String {
        if let booleanValue = (self as? Bool) {
            return String(format: (booleanValue ? "true" : "false"))
        }
        else
        if let intValue = (self as? Int) {
            return String(format: "%d", intValue)
        }
        else
        if let floatValue = (self as? Float) {
            return String(format: "%f", floatValue)
        }
        else
        if let doubleValue = (self as? Double) {
            return String(format: "%f", doubleValue)
        }
        else
        {
            return String(format: "<%@>", self)
        }
    }
}

就像我想在字典(自身)中使用它到xml字符串工厂一样

extension Dictionary {
    //  Return an XML string from the dictionary
    func xmlString(withElement element: String, isFirstElement: Bool) -> String {
        var xml = String.init()

        if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }

        xml.append(String(format: "<%@>\n", element))
        for node in self.keys {
            let value = self[node]

            if let array: Array<Any> = (value as? Array<Any>) {
                xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
            }
            else
            if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
                xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
            }
            else
            {
                xml.append(String(format: "<%@>", node as! CVarArg))
                xml.append((value as Any).literal
                xml.append(String(format: "</%@>\n", node as! CVarArg))
            }
        }

        xml.append(String(format: "</%@>\n", element))

        return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
    }
}

我正在尝试以某种方式减少代码,因为上述代码段在我正在构建的原型中重复了几次,但这不是做到这一点的方式(带有代码段复制品的工作副本,但是很丑吗?)

基本上,我想为Any值生成一个文字-以前是从字典中获取的。

2 个答案:

答案 0 :(得分:0)

好像你can't add extensions to Any。但是,您还有其他选择-将其设置为函数toLiteral(value: Any) -> String,或者可能更整洁的解决方案;使用description: String属性,该属性存在于符合CustomStringConvertible的所有类型上,包括StringIntBoolFloat-您的代码将简化为xml.append(value.description)。然后,您只需对可能得到的任何其他类型进行简单的实现即可。

答案 1 :(得分:0)

好吧,终于成功了。首先是预备知识:每个对象都需要有一个dictionary()方法来编组自己。注意:“ k。###”是结构静态常量-即k.name是“ name”,等等。我有两个对象,一个PlayItem和一个PlayList:

class PlayItem : NSObject {
    var name : String = k.item
    var link : URL = URL.init(string: "http://")!
    var time : TimeInterval
    var rank : Int
    var rect : NSRect
    var label: Bool
    var hover: Bool
    var alpha: Float
    var trans: Int
    var temp : String {
        get {
            return link.absoluteString
        }
        set (value) {
            link = URL.init(string: value)!
        }
    }

    func dictionary() -> Dictionary<String,Any> {
        var dict = Dictionary<String,Any>()
        dict[k.name] = name
        dict[k.link] = link.absoluteString
        dict[k.time] = time
        dict[k.rank] =  rank
        dict[k.rect] = NSStringFromRect(rect)
        dict[k.label] = label ? 1 : 0
        dict[k.hover] = hover ? 1 : 0
        dict[k.alpha] = alpha
        dict[k.trans] = trans
        return dict
    }
}

class PlayList : NSObject {
    var name : String = k.list
    var list : Array <PlayItem> = Array()

    func dictionary() -> Dictionary<String,Any> {
        var dict = Dictionary<String,Any>()
        var items: [Any] = Array()
        for item in list {
            items.append(item.dictionary())
        }
        dict[k.name] = name
        dict[k.list] = items
        return dict
    }
}

注意的任何值,使元数据必须成为字典的合法类型;它有助于别名,因此在PlayItem中,“ temp”是链接网址的字符串版本,其getter / setter会翻译。

在需要时,例如执行writeRowsWith拖放式tableview处理程序,

    func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {

        if tableView == playlistTableView {
            let objects: [PlayList] = playlistArrayController.arrangedObjects as! [PlayList]
            var items: [PlayList] = [PlayList]()
            var promises = [String]()

            for index in rowIndexes {
                let item = objects[index]
                let dict = item.dictionary()
                let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
                promises.append(promise)
                items.append(item)
            }

            let data = NSKeyedArchiver.archivedData(withRootObject: items)
            pboard.setPropertyList(data, forType: PlayList.className())
            pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
            pboard.writeObjects(promises as [NSPasteboardWriting])
        }
        else
        {
            let objects: [PlayItem] = playitemArrayController.arrangedObjects as! [PlayItem]
            var items: [PlayItem] = [PlayItem]()
            var promises = [String]()

            for index in rowIndexes {
                let item = objects[index]
                let dict = item.dictionary()
                let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
                promises.append(promise)
                items.append(item)
            }

            let data = NSKeyedArchiver.archivedData(withRootObject: items)
            pboard.setPropertyList(data, forType: PlayList.className())
            pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
            pboard.writeObjects(promises as [NSPasteboardWriting])
        }
        return true
    }

发生这种情况的原因是这些xmlString扩展和toLiteral函数-因为您无法扩展“任何”:

func toLiteral(_ value: Any) -> String {
    if let booleanValue = (value as? Bool) {
        return String(format: (booleanValue ? "1" : "0"))
    }
    else
    if let intValue = (value as? Int) {
        return String(format: "%d", intValue)
    }
    else
    if let floatValue = (value as? Float) {
        return String(format: "%f", floatValue)
    }
    else
    if let doubleValue = (value as? Double) {
        return String(format: "%f", doubleValue)
    }
    else
    if let stringValue = (value as? String) {
        return stringValue
    }
    else
    if let dictValue: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>)
    {
        return dictValue.xmlString(withElement: "Dictionary", isFirstElement: false)
    }
    else
    {
        return ((value as AnyObject).description)
    }
}

extension Array {
    func xmlString(withElement element: String, isFirstElemenet: Bool) -> String {
        var xml = String.init()

        xml.append(String(format: "<%@>\n", element))
        self.forEach { (value) in
            if let array: Array<Any> = (value as? Array<Any>) {
                xml.append(array.xmlString(withElement: "Array", isFirstElemenet: false))
            }
            else
            if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
                xml.append(dict.xmlString(withElement: "Dictionary", isFirstElement: false))
            }
            else
            {
                xml.append(toLiteral(value))
            }
        }
        xml.append(String(format: "<%@>\n", element))

        return xml
    }
}

extension Dictionary {
    //  Return an XML string from the dictionary
    func xmlString(withElement element: String, isFirstElement: Bool) -> String {
        var xml = String.init()

        if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }

        xml.append(String(format: "<%@>\n", element))
        for node in self.keys {
            let value = self[node]

            if let array: Array<Any> = (value as? Array<Any>) {
                xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
            }
            else
            if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
                xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
            }
            else
            {
                xml.append(String(format: "<%@>", node as! CVarArg))
                xml.append(toLiteral(value as Any))
                xml.append(String(format: "</%@>\n", node as! CVarArg))
            }
        }

        xml.append(String(format: "</%@>\n", element))

        return xml
    }
    func xmlHTMLString(withElement element: String, isFirstElement: Bool) -> String {
        let xml = self.xmlString(withElement: element, isFirstElement: isFirstElement)

        return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
    }
}

这将继续另一个解决方案,即上面的toLiteral()建议,希望对其他人有所帮助。

享受。