Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
解析真正复杂的json?敏捷的_Json_Swift - Fatal编程技术网

解析真正复杂的json?敏捷的

解析真正复杂的json?敏捷的,json,swift,Json,Swift,我正在尝试解析此json: { "objName": "Stage", "sounds": [{ "soundName": "pop", "soundID": 0, "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", "sampleCount": 258, "rate": 11025, "format": "" }], "costumes": [{

我正在尝试解析此json:

{
"objName": "Stage",
"sounds": [{
        "soundName": "pop",
        "soundID": 0,
        "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
        "sampleCount": 258,
        "rate": 11025,
        "format": ""
    }],
"costumes": [{
        "costumeName": "backdrop1",
        "baseLayerID": 6,
        "baseLayerMD5": "b61b1077b0ea1931abee9dbbfa7903ff.png",
        "bitmapResolution": 2,
        "rotationCenterX": 480,
        "rotationCenterY": 360
    }],
"currentCostumeIndex": 0,
"penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png",
"penLayerID": 0,
"tempoBPM": 60,
"videoAlpha": 0.5,
"children": [{
        "objName": "img",
        "scripts": [[5, 5, [["whenGreenFlag"], ["setSizeTo:", 101], ["gotoX:y:", 0, 0]]]],
        "sounds": [{
                "soundName": "pop",
                "soundID": 0,
                "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
                "sampleCount": 258,
                "rate": 11025,
                "format": ""
            }],
        "costumes": [{
                "costumeName": "dotstickie3",
                "baseLayerID": 1,
                "baseLayerMD5": "bcea2c64c030a2d1ebd7be5ced828583.png",
                "bitmapResolution": 2,
                "rotationCenterX": 480,
                "rotationCenterY": 360
            }],
        "currentCostumeIndex": 0,
        "scratchX": 0,
        "scratchY": 0,
        "scale": 1.01,
        "direction": 90,
        "rotationStyle": "normal",
        "isDraggable": false,
        "indexInLibrary": 1,
        "visible": true,
        "spriteInfo": {
        }
    },
    {
        "objName": "drag",
        "scripts": [[5,
                5,
                [["whenGreenFlag"], ["setSizeTo:", 101], ["gotoX:y:", -413, -7], ["comeToFront"]]],
            [10,
                129,
                [["whenIReceive", "slide"],
                    ["doRepeat",
                        23,
                        [["gotoX:y:",
                                ["+", ["xpos"], ["\/", ["-", 40, ["xpos"]], 7]],
                                -7]]]]]],
        "sounds": [{
                "soundName": "pop",
                "soundID": 0,
                "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
                "sampleCount": 258,
                "rate": 11025,
                "format": ""
            }],
        "costumes": [{
                "costumeName": "dotstickie3",
                "baseLayerID": 2,
                "baseLayerMD5": "e822121ae459cc14df1a5609abe4fd39.svg",
                "bitmapResolution": 1,
                "rotationCenterX": 296,
                "rotationCenterY": 189
            }],
        "currentCostumeIndex": 0,
        "scratchX": 26.928601934244593,
        "scratchY": -7,
        "scale": 1.01,
        "direction": 90,
        "rotationStyle": "normal",
        "isDraggable": false,
        "indexInLibrary": 2,
        "visible": true,
        "spriteInfo": {
        }
    },
    {
        "objName": "clicktostart",
        "scripts": [[5,
                7,
                [["whenGreenFlag"],
                    ["hide"],
                    ["wait:elapsed:from:", 1],
                    ["comeToFront"],
                    ["setGraphicEffect:to:", "ghost", 100],
                    ["show"],
                    ["doRepeat", 25, [["changeGraphicEffect:by:", "ghost", -4]]],
                    ["doWaitUntil", ["mousePressed"]],
                    ["doRepeat", 25, [["changeGraphicEffect:by:", "ghost", 4]]],
                    ["hide"],
                    ["broadcast:", "slide"]]]],
        "sounds": [{
                "soundName": "pop",
                "soundID": 0,
                "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
                "sampleCount": 258,
                "rate": 11025,
                "format": ""
            }],
        "costumes": [{
                "costumeName": "costume1",
                "baseLayerID": 3,
                "baseLayerMD5": "826c7f77077cfba8abddeae0229caf22.svg",
                "bitmapResolution": 1,
                "rotationCenterX": 139,
                "rotationCenterY": -60
            },
            {
                "costumeName": "costume2",
                "baseLayerID": 4,
                "baseLayerMD5": "a1c639c03c30e32b5baf48ea18621bc4.png",
                "bitmapResolution": 2,
                "rotationCenterX": 278,
                "rotationCenterY": -132
            }],
        "currentCostumeIndex": 1,
        "scratchX": 69,
        "scratchY": -30,
        "scale": 1,
        "direction": 90,
        "rotationStyle": "normal",
        "isDraggable": false,
        "indexInLibrary": 3,
        "visible": false,
        "spriteInfo": {
        }
    },
    {
        "objName": "Sprite1",
        "sounds": [{
                "soundName": "pop",
                "soundID": 0,
                "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
                "sampleCount": 258,
                "rate": 11025,
                "format": ""
            }],
        "costumes": [{
                "costumeName": "costume1",
                "baseLayerID": 5,
                "baseLayerMD5": "7e82b18194f5cc47fba05a7ee5420172.svg",
                "bitmapResolution": 1,
                "rotationCenterX": 113,
                "rotationCenterY": 86
            }],
        "currentCostumeIndex": 0,
        "scratchX": -35,
        "scratchY": 21,
        "scale": 1,
        "direction": 90,
        "rotationStyle": "normal",
        "isDraggable": false,
        "indexInLibrary": 4,
        "visible": true,
        "spriteInfo": {
        }
    }],
"info": {
    "spriteCount": 4,
    "userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/67.0.3396.99 Safari\/537.36",
    "scriptCount": 4,
    "projectID": "239379933",
    "hasCloudData": true,
    "swfVersion": "v461",
    "videoOn": false,
    "flashVersion": "MAC 30,0,0,154"
}
}

我查阅了如何解析复杂的json,大多数答案告诉我创建一个
struct
,并尝试尽可能地匹配数据,因此我创建了以下内容:

fileprivate struct Stage: Decodable {
struct Sound: Decodable {
    var soundName: String;
    var soundID: Int;
    var md5: String;
    var sampleCount: Int;
    var rate: Int;
    var format: String;
}

struct Costume: Decodable {
    var costumeName: String;
    var baseLayerID: Int;
    var baseLayerMD5: String;
    var bitmapResolution: Int;
    var rotationCenterX: Int;
    var rotationCenterY: Int;
}

struct Child: Decodable {
    var objName: String;
    var scripts: [[Any]];
    var sounds: [Sound];
    var costumes: [Costume];
    var currentCostumeIndex: Int;
    var scratchX: Int;
    var scratchY: Int;
    var scale: Float;
    var direction: Int;
    var rotationStyle: String;
    var isDraggable: Bool;
    var indexInLibrary: Int;
    var visible: Bool;
    var spriteInfo: SpriteInfo;
}
struct SpriteInfo: Decodable {

}
struct Info: Decodable {
    var spriteCount: Int;
    var userAgent: String;
    var scriptCount: Int;
    var projectID: String;
    var hasCloudData: Bool;
    var swfVersion: String;
    var videoOn: Bool;
    var flashVersion: String;
}

var objName: String;
var sounds: [Sound];
var costumes: [Costume];
var currentCostumeIndex: Int;
var penLayerMD5: String;
var penLayerID: Int;
var tempoBPM: Int;
var videoAlpha: Float;
var children: [Child];
var info: Info;
}

当我编译swift时,它会说“错误:类型'Stage.Child'不符合协议'Decodable'”

我不知道该怎么解决这个问题

任何帮助都将不胜感激。

简单的部分 正如其他人所说,问题在于如何解码
脚本
属性。JSON的其余部分非常传统,因此我将它们粘贴到其中,得到了以下结构:

struct Stage: Decodable {
    let objName: String
    let sounds: [Sound]
    let costumes: [Costume]
    let currentCostumeIndex: Int
    let penLayerMD5: String
    let penLayerID, tempoBPM: Int
    let videoAlpha: Double
    let children: [Child]
    let info: Info
}

struct Child: Decodable {
    let objName: String
    let scripts: [Script]?  // We will write a custom decoder for `Script`
    let sounds: [Sound]
    let costumes: [Costume]
    let currentCostumeIndex: Int
    let scratchX: Double
    let scratchY: Int
    let scale: Double
    let direction: Int
    let rotationStyle: String
    let isDraggable: Bool
    let indexInLibrary: Int
    let visible: Bool
    let spriteInfo: SpriteInfo
}

struct Costume: Decodable {
    let costumeName: String
    let baseLayerID: Int
    let baseLayerMD5: String
    let bitmapResolution, rotationCenterX, rotationCenterY: Int
}

struct Sound: Decodable {
    let soundName: String
    let soundID: Int
    let md5: String
    let sampleCount, rate: Int
    let format: String
}

struct SpriteInfo: Decodable { }

struct Info: Decodable {
    let spriteCount: Int
    let userAgent: String
    let scriptCount: Int
    let projectID: String
    let hasCloudData: Bool
    let swfVersion: String
    let videoOn: Bool
    let flashVersion: String
}
解码
脚本
本节中所有与
CustomDebugStringConvertible
的符合性都是可选的。代码工作时不必包含它们。它们仅用于协助调试

脚本
对象 下面的3个实例都表示
脚本的有效数组

// Example 1
[
    [5, 5, [["whenGreenFlag"], ["setSizeTo:", 101], ["gotoX:y:", 0, 0]]]
]

// Example 2
[
    [5, 7, [["whenGreenFlag"],["hide"],["wait:elapsed:from:",1],["comeToFront"],["setGraphicEffect:to:","ghost",100],["show"],["doRepeat",25,[["changeGraphicEffect:by:","ghost",-4]]],["doWaitUntil",["mousePressed"]],["doRepeat",25,[["changeGraphicEffect:by:","ghost",4]]],["hide"],["broadcast:","slide"]]]
]

// Example 3:
[
    [5, 5, [["whenGreenFlag"], ["setSizeTo:", 101], ["gotoX:y:", -413, -7], ["comeToFront"]]],
    [10, 129, [["whenIReceive", "slide"], ["doRepeat", 23, [["gotoX:y:", ["+", ["xpos"], ["/", ["-", 40, ["xpos"]], 7]], -7]]]]]
]
从这些示例中,我们可以看到一个
脚本
以2个数字开始,然后是一个似乎是命令的数组,因此我们可以像这样解码
脚本

struct Script: Decodable, CustomDebugStringConvertible {
    var firstNumber: Int
    var secondNumber: Int
    var commands: [Command]

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()

        self.firstNumber = try container.decode(Int.self)
        self.secondNumber = try container.decode(Int.self)
        self.commands = try container.decode([Command].self)
    }

    var debugDescription: String {
        return "Script: \(firstNumber), \(secondNumber), \(commands.debugDescription)"
    }
}
命令
对象 转到
命令
,以下是一些示例:

["whenGreenFlag"]
["setSizeTo:", 101]
["whenIReceive", "slide"]
["gotoX:y:", 0, 0]
["doRepeat",25,[["changeGraphicEffect:by:","ghost",4]]]
因此,每个
命令都以一个字符串开头,后跟0个或更多参数。每个
参数
可以是整数、字符串或另一个
命令

struct Command: Decodable, CustomDebugStringConvertible {
    var name: String
    var arguments = [CommandArgument]()

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()

        self.name = try container.decode(String.self)
        while !container.isAtEnd {
            let argument = try container.decode(CommandArgument.self)
            self.arguments.append(argument)
        }
    }

    var debugDescription: String {
        return "(\(name) \(arguments.debugDescription))"
    }
}
CommandArgument
对象
CommandArgument
s的示例:

101
"slide"
["doRepeat", 23, [["gotoX:y:", ["+", ["xpos"], ["/", ["-", 40, ["xpos"]], 7]], -7]]]
每个
CommandArgument
都可以是整数、字符串或其他命令。我们将使用具有关联值的枚举来表示它:

enum CommandArgument: Decodable, CustomDebugStringConvertible {
    case integer(value: Int)
    case string(value: String)
    case command(value: Command)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let intValue = try? container.decode(Int.self) {
            self = .integer(value: intValue)
        } else if let stringValue = try? container.decode(String.self) {
            self = .string(value: stringValue)
        } else if let commandValue = try? container.decode(Command.self) {
            self = .command(value: commandValue)
        } else if let commandArray = try? container.decode([Command].self) {
            self = .command(value: commandArray.first!)
        } else {
            throw NSError(domain: NSCocoaErrorDomain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Unrecognized argument type"])
        }
    }

    var debugDescription: String {
        switch self {
        case .integer(let intValue):
            return "\(intValue)"
        case .string(let stringValue):
            return stringValue
        case .command(let commandValue):
            return commandValue.debugDescription
        }
    }
}
最后 现在您已经编写了所有代码,下面是如何解码整个JSON:

let stage = try JSONDecoder().decode(Stage.self, from: json)

首先,这不是JavaScript或Objective-C。Swift中没有尾随分号!其次,
Codable
不支持
Any
@vadian如果Codable不支持任何,我会使用什么?通常的方法是通过删除属性来隔离问题,直到问题消失……正如@MartinR所说,不要首先解析
script
。现在它起作用了吗?因为目前看来这是唯一的问题。如果是,让我们关注
脚本
,但您可以删除所有其他键,在一个侧项目上使用一个只包含脚本和自定义类的测试json。@Larme脚本是个问题,因为它具有任意类型。我尝试了类似这样的操作,但它说类似于
函数的东西。decode()”不存在
。我需要导入一些框架吗?
importfoundation
是我使用的全部。你能发布给你错误的代码行吗?这一行似乎没有给我任何错误。这是我从另一个问题中得到的代码,给出了这个错误。有没有办法删除可选的([Script:5,5…]),这样它就是[Script:5,5…],我今晚会看一看