swift 使用decoder和do、try阅读JSON时,catch块数据在块外部不可用

dsf9zpds  于 2023-03-07  发布在  Swift
关注(0)|答案(3)|浏览(99)

我正在尝试使用包含json数据的文本文件中的数据。从各种来源,我能够成功地从文件中读取数据数组。但是,当我尝试在另一个do,try,catch块中使用函数之外的代码时,它会抱怨“变量xxx在初始化之前使用”
看看这里发布的答案,说要在do,try,catch块之外创建变量,但它只是移动了错误。

快速5(5.7.1)

CLI学习应用程序

单位. json

这是包含元素数组的示例JSON文件。

{
    "units": [
        {
            "name":"cartman",
        },
        {
            "name":"kyle",
        }
    ]
}

文件IO.swift

这是执行fileIO的代码

import Foundation

// src https://stackoverflow.com/a/36827996/1008596
struct UnitData: Decodable {
    var name: String = "none"
}

struct UnitsData: Decodable {
    var units: [UnitData]
}


enum JFDFileError: Error {
    case FileNotFound
    case JSONDecodeFailed
}

// src https://www.swiftbysundell.com/articles/working-with-files-and-folders-in-swift/
func my_simple_file_read(path: String) throws -> UnitsData {
        
    let file_name = (path as NSString).expandingTildeInPath
    let url = URL(fileURLWithPath: file_name)
    
    // Read the file
    var data: Data
    do {
        data = try Data(contentsOf: url)
    } catch {
        throw JFDFileError.FileNotFound
    }

    var unitsData: UnitsData
    do {
        let decoder = JSONDecoder()
        unitsData = try decoder.decode(UnitsData.self, from: data)
        // these prints work
        // prints entire json file
        print("entire json file \(unitsData)")
        // prints specific element of json array
        print("this works 0 is \(unitsData.units[1].name)")
    } catch {
        throw JFDFileError.JSONDecodeFailed
    }
    // this print works
    print("this works here \(unitsData.units[1].name)")
    return unitsData
    
}

主.快速

这是主代码的一个摘录。它和函数的形式一样,但是函数调用的返回失败了。为什么?

// Read units from json file
    var unitsData: UnitsData
    do {
        unitsData = try  my_simple_file_read(path: "~/somepath/units.json")
        // this works
        print("works1 is \(unitsData.units[1].name)")
        
    } catch {
        print("an error occured")
    }
    
    // error: Variable 'unitsData' used before being initialized

    print("does not work \(unitsData.units[1].name)")
h5qlskok

h5qlskok1#

关于Main.swift中的编译时错误:
变量“unitsData”在初始化前使用
这是因为你有一个执行路径(try my_simple_file_read可能会抛出错误),其中unitsData变量没有设置。所有的执行路径必须设置变量,否则编译器将生成一个错误,就像你在这里看到的。
do-catch语句之后避免引用unitsData(即,将所有unitsData引用 * 放入 * do块),或者在捕获到错误时退出,或者使unitsData成为可选项并将其设置为catch块中的nil
函数实现的不同之处在于,如果捕捉到错误(在catch语句中是throw,它会立即退出),并且没有到达函数中的最后一条print语句,则会有一个“早期退出”,因此在变量初始化之前没有使用它。
这与Main.swift示例形成对比,在catch示例中,catch语句只打印一条消息并继续执行,到达一个从未设置的unitsData引用。编译器检测到这种误用并生成编译时错误。

snvhrwxg

snvhrwxg2#

首先,John Sundell是一位严肃而可敬的Swift开发人员,他绝不会建议使用my_simple_file_read(这样的snake_case函数名,也不会通过打印无意义的字符串文字来丢弃错误。
基本上,声明一个没有默认值的变量只有在保证变量在某个地方被初始化的情况下才有意义。

var unitsData: UnitsData
do {
    unitsData = try my_simple_file_read(path: "~/somepath/units.json")
    // this works
    print("works1 is \(unitsData.units[1].name)")
    
} catch {
   unitsData = UnitsData(units: [])
   print(error)
}

编译器会抛出一个错误,因为您没有在catch块中赋值。
但是在您的情况下,在do范围内声明并初始化变量常量

do {
    let unitsData = try my_simple_file_read(path: "~/somepath/units.json")
    print("works1 is \(unitsData.units[1].name)")
    
} catch {
    print(error)
}

无论如何,如果函数throws是一个更好的实现

func mySimpleFileRead(path: String) throws -> UnitsData {
        
    let fileName = (path as NSString).expandingTildeInPath
    let url = URL(fileURLWithPath: fileName)
   
    let data = try Data(contentsOf: url)
    return try JSONDecoder().decode(UnitsData.self, from: data)
}

框架引发的错误比自定义错误更严重。

vql8enpb

vql8enpb3#

我今天学到了一些东西:

  • 有一个聊天选项可以使用。话虽如此,罗布和瓦迪恩,帮助我互动。
  • do catch块外的print在fileIO函数中起作用,但在调用该函数的主代码中不起作用,原因是我在catch块中有一个简单的print,并且没有重新抛出错误。这意味着如果发生错误,结构没有初始化,并且在运行时数组将是未定义的。令人惊讶的是,编译器可以区分这一点。

话虽如此,是解决方案,它演示了更好的方法来编写初始函数和原始函数,以显示为什么它的工作方式之一,而不是其他。即工作在原始代码与抛出,但不打印。

文件.swift

func my_simple_file_read(path: String) throws -> UnitsData {

    print("path is \(path)")
    
    let file_name = (path as NSString).expandingTildeInPath
    print("file_name is \(file_name)")

    
    let url = URL(fileURLWithPath: file_name)
    print("url is \(url)")
    
    // Read the file
    var data: Data
    do {
        data = try Data(contentsOf: url)
        print("data is \(data)")
    } catch {
        throw JFDFileError.FileNotFound
    }

    var unitsData: UnitsData
    do {
        let decoder = JSONDecoder()
        unitsData = try decoder.decode(UnitsData.self, from: data)
        print("json data is \(unitsData)")
        print("json data.name is \(unitsData.units[1].name)")
    } catch {
        throw JFDFileError.JSONDecodeFailed
    }



    print("===.name is \(unitsData.units[1].name)")
    return unitsData
    
}

func mySimpleFileRead(path: String) throws -> UnitsData {
        
    let fileName = (path as NSString).expandingTildeInPath
    let url = URL(fileURLWithPath: fileName)
   
    let data = try Data(contentsOf: url)
    return try JSONDecoder().decode(UnitsData.self, from: data)
}

主.快速

func doThing(id1:Int, id2:Int) throws -> (Int, Int) {
    print("-----")

    // Read units from json file
    var unitsData: UnitsData
    do {
        unitsData = try  my_simple_file_read(path: "~/somepath/units.json")
        print("=++++==.name is \(unitsData.units[1].name)")

        
    } catch {
        throw JFDFileError.JSONDecodeFailed
    }
    
    print("1=-+-+==.name is \(unitsData.units[1].name)")

    var unitsData2: UnitsData
    do {
        unitsData2 = try mySimpleFileRead(path: "~/progs/myxcode/ogrev1/ogrev1/ogrev1/units.json")
    } catch {
        throw JFDFileError.JSONDecodeFailed
    }
    
    print("2=-+-+==.name is \(unitsData2.units[1].name)")
...
...
...

相关问题