无法将文本文件读入所需的数组格式

Trouble reading in text file into needed array format

我正在尝试压缩我正在处理的应用程序,该应用程序涉及一个包含大量 UIViewControllersUITableViews 的大目录。

我的计划是重写将使用一次性 UIViewControllerUITableView 的应用程序,它将根据需要从 txt 文件加载数据 at/after 运行时。 txt 文件将在 at/after 运行时读取,而不是必须事先构建所有 swift 文件。

目前,每次我对项目进行更改时,我的应用程序都需要几分钟才能 build/compile 。因此,我希望通过根据需要读取和解析 txt 文件,我将能够在短短几秒钟内构建应用程序。

下面是我尝试使用下面提供的示例文本文件 (candyTextFile.txt) 读取和生成必要的 "candies" 数组。 请参阅 class、MasterViewController 中的注释行,了解错误消息和我尝试将糖果数组输出为的代码。

请注意,我已将文本文件中的行缩短为三行。我的最终应用程序将包含许多类似的文本文件,每个文件都扩展了数百行。

我对 Swift 还是比较陌生,所以如果我在这里遗漏了一些简单的东西,如果我是 using/not-using 适当的术语,我深表歉意。

我相信术语 CandySearch 只是来自项目名称(请参阅 here)。我不确定为什么它会在 candies 数组中输出。另外,我现在确实看到我当前的 myArray 被确定为 class。我怎样才能把它变成一个数组?

这是我的相关代码 MasterViewController.swift,

class MasterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var candies = [myArray]()
    var evenIndicies = [String]()
    var oddIndicies = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        setUpArray()
    }

    private func setUpArray() {
        if let filepath = Bundle.main.path(forResource: "candyTextFile", ofType: "txt") {
            do {
                // let contents = try String(contentsOfFile: "candyTextFile", encoding: String.Encoding.utf8)
                let contents = try String(contentsOfFile: filepath)
                let lines_separatedBy_n : [String] = contents.components(separatedBy: "\n")
                let string = lines_separatedBy_n.map { String([=10=]) }.joined(separator: ", ")
                print("string: \(string)")
                let lines_separatedBy_comma : [String] = string.components(separatedBy: ", ")
                print("lines_separatedBy_comma: \(lines_separatedBy_comma)")

                for (index, element) in lines_separatedBy_comma.enumerated() {
                    if index % 2 == 0 {
                        evenIndicies.append(element)
                        print("evenIndicies: \(evenIndicies)")

                    } else {
                        oddIndicies.append(element)
                        print("oddIndicies: \(oddIndicies)")
                    }
                }
                evenIndicies.remove(at: evenIndicies.count - 1) // the -1 removes the nil element, "", in the array. For some reason, there is a fourth element, "", in the evenIndicies array. Therefore, I remove it by subtracting one index so I get the three indexes. My in project txt file is four lines long where the fourth line is empty. I think this is why it is showing up "" for the fourth index.
                print("evenIndicies outside for-loop: \(evenIndicies)")
                print("oddIndicies outside for-loop: \(oddIndicies)")
                candies = [myArray(category: evenIndicies, name: oddIndicies)]  // 

                print("candies: \(candies)") 
           // This prints as the following:
           // candies: [CandySearch.myArray]

           // HOWEVER, I am trying to get it to print as: 
           // [CandySearch.myArray(category: "Chocolate", name: "Chocolate Bar"), CandySearch.myArray(category: "Chocolate", name: "Chocolate Cookie"), CandySearch.myArray(category: "Hard", name: "Lollipop")]




            } catch let error as NSError {
                print(error.localizedDescription)
            }
        }
    }
}

class myArray {
    let category: [String]
    let name: [String]
    init(category: [String], name: [String]) {
        self.category = category
        self.name = name
    }
}

在我的文本文件中,candyTextFile.txt,我有

Chocolate, Chocolate Bar
Chocolate, Chocolate Cookie
Hard, Lollipop

假设您想要做的是从文本文件中获取信息并最终得到一系列糖果产品,我将尝试一下。目前你的 myArray class 看起来有点像弗兰肯斯坦的东西。它在 class 的单个实例中包含两个单独数组中的所有类别和名称。然后将其放入一个名为 candies 的数组中。除非我误解了您的要求,否则这一切看起来都是死胡同。 (也许我是。)但假设我至少对了一半...

你想要一堆糖果,所以让我们制作一个新的 class 来装一颗糖果。

class Candy {
    let category: String!
    let name: String!

    init(category: String, name: String) {
        self.category = category
        self.name = name
    }
}

这与您已有的类似,但是当您实例化 Candy 的实例时,它将保存单个糖果的详细信息。注意 class 名称按照惯例以大写字母开头。

你想以糖果数组结束,所以让我们改变你的 candies 数组的定义。

var candies: [Candy] = []

剩下的就是更改 for in 循环以在每个循环中提取一个糖果的数据(类别和名称),创建一个新的 Candy 实例并在将其添加到 candies.

for (index, element) in lines_separatedBy_comma.enumerated() {
   var newCategory = ""
   var newName = ""
   if index % 2 == 0 {
      newCategory = element
   } else {
      newName = element
   }
   let newCandy = Candy(category: newCategory, name: newName)
   candies.append(newCandy)
}

您的代码中没有任何可处理文本文件中任何 errors/bad 格式的代码,因此我假设您完全确定它是由成对的数据组成的,没有松散的结尾等。我看到你出于某种原因删除了 evenIndices 的最后一个元素。我不确定为什么,所以我没有处理它。

现在你的 candies 数组应该包含一堆 Candy 对象,所以要将它们列出到控制台,你可以这样做。

for candy in candies {
   print("category: \(String(describing: candy.category)), name: \(String(describing: candy.name))")
}

让我知道我是否仍未达到目标。

编辑 ******************************************** ************ 编辑

我看了你链接的RW教程。

本教程使用 struct 作为 Candy 元素,而您(和我)使用的是 class。我猜你还在学习 Swift 的值和引用类型,所以不要把这里的水弄混了。可以说 struct 在这种情况下可能会更好。 print 也以不同的方式处理它们并且似乎能够在结构内部查找值,而除非您显式提取属性(如在我的 for in 打印语句中,它只为您提供 class如我们所见。

我也整理了逻辑(它很丑陋,你不应该这样做)所以你至少可以看到它确实有效(在时尚之后)。整个setupArray方法:

private func setupArray() {
     if let filepath = Bundle.main.path(forResource: "candyTextFile", ofType: "txt") {
         do {
             let contents = try String(contentsOfFile: filepath)
             let lines_separatedBy_n : [String] = contents.components(separatedBy: "\n")
             let string = lines_separatedBy_n.map { String([=14=]) }.joined(separator: ", ")
             var lines_separatedBy_comma : [String] = string.components(separatedBy: ", ")

             // I've put this in to remove the last bit of the file that was causing the count to be one too high.
             // I'm guessing that's why you had something similar previously?
             lines_separatedBy_comma.removeLast()

             for (index, element) in lines_separatedBy_comma.enumerated() {
                 if index % 2 == 0 {
                     let newCategory = element
                     let newName = lines_separatedBy_comma[index + 1]
                     let newCandy = Candy(category: newCategory, name: newName)
                     candies.append(newCandy)
                 }
             }
             for candy in candies {
                 print("category: \(candy.category!), name: \(candy.name!)")
             }
             print("\ncandies: \(candies)")
         } catch let error as NSError {
             print(error.localizedDescription)
         }
     }
 }

当我使用:

class Candy {
    let category: String!
    let name: String!

    init(category: String, name: String) {
        self.category = category
        self.name = name
    }
}

输出为:

category: Chocolate, name: Chocolate Bar
category: Chocolate, name: Chocolate Cookie
category: Hard, name: Lollipop

candies: [FileTest.Candy, FileTest.Candy, FileTest.Candy]

当我使用时:(从 print 语句中删除强制展开后)

struct Candy {
    let category : String
    let name : String
}

输出为:

category: Chocolate, name: Chocolate Bar
category: Chocolate, name: Chocolate Cookie
category: Hard, name: Lollipop

candies: [FileTest.Candy(category: "Chocolate", name: "Chocolate Bar"), FileTest.Candy(category: "Chocolate", name: "Chocolate Cookie"), FileTest.Candy(category: "Hard", name: "Lollipop")]

您是否看到您的原始代码将所有内容都放在一个 myArray 中,但是上面的代码(以及在 RW 站点上)创建了单独的 Candy 元素并将它们全部存储到 candies?这是方法上的根本区别。