在Swift中,我如何仅从.json文件

时间:2016-03-03 11:54:15

标签: json swift

好的,所以我在过去的几个月里一直在学习如何在业余时间进行编程,而我现在正试图了解如何仅使用来自.json文件的数据已被过滤。

例如,假设我有一个.json文件,格式如下:

    {
        "id" : "1",
        "question": "Earth is a:",
             "answers": [
            "Planet",
            "Meteor",
            "Star",
            "Asteroid"
          ],
        "category": "astronomy"
    },
    {
        "id":"2",
        "question":"Which country won the 2006 Soccer World Cup?",
        "answers":[
            "Italy",
            "Germany",
            "France",
            "Brazil"
            ],
        "category": "sport"
 }

我的问题

假设我将所有数据都放在一个.json文件中,如何只加载 符合特定条件的数据,加载所有数据,然后只选择符合特定标准的数据?显然,最终结果必须是只将过滤后的数据混洗并显示给用户。

道歉,如果这是显而易见的,但作为一个新手,我只是没有知识/经验来找到比我下面描述的多文件方法更好的方法。我确实试着寻找答案,但是找不到一个似乎适用于我的场景的答案。如果有,我已经错过了,请转发给我。

某些背景

目前我使用以下代码加载我的数据:

  func LoadAllQuestionsAndAnswers()
    {
        let path = NSBundle.mainBundle().pathForResource("content", ofType: "json")
        let jsonData : NSData = NSData(contentsOfFile: path!)!
        allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
        //println(allEntries)

    }

显然,上面的从.json文件加载所有数据。加载此数据后,我将使用以下代码重新调整所有问题:

if #available(iOS 9.0, *) {
            shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
            nextQuestion++
            LoadQuestion(nextQuestion)

            // Fallback on earlier versions
        }else{

            let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
            LoadQuestionPreiOS9(randomNumber)

        }

一旦洗牌,我就会使用以下代码向用户提出问题:

func LoadQuestion(index : Int)
{
    let entry : NSDictionary = shuffledQuestions[index] as! NSDictionary
    let question : NSString = entry.objectForKey("question") as! NSString
    let arr : NSMutableArray = entry.objectForKey("answers") as! NSMutableArray

    let QID : NSString = entry.objectForKey("id") as! NSString

    if let a = arr.objectAtIndex(0) as? String {
        self.answertext = a
    }

    //println(question)
    //println(arr)

    labelQuestion.text = question as String
    labelQID.text = QID as String

所以,我想做的是让用户选择他们想要回答的问题类别。现在显然我可以通过为每个类别使用单独的.json文件并使用if else语句来完成此操作。例如,我可以有一个astronomy.json文件,一个sport.json文件等,然后使用如下代码:

    func LoadChosenCategory()
    {
        let defaults = NSUserDefaults.standardUserDefaults()

        if (chosencategory == 1)
        {
let path = NSBundle.mainBundle().pathForResource("astronomy", ofType: "json")
        let jsonData : NSData = NSData(contentsOfFile: path!)!
        allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
        //println(allEntries)

        }else{

            if (lastchosenchallenge == 2)
            {
let path = NSBundle.mainBundle().pathForResource("sport", ofType: "json")
        let jsonData : NSData = NSData(contentsOfFile: path!)!
        allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
        //println(allEntries)

            }else{

依此类推。

但我相信必须有更有效的方法来做到这一点,我想学习如何,因此这个问题。

好的,所以我试图按照Russell的回答中的建议,但是不能让它发挥作用。它运行良好,但似乎并没有真正过滤数据。

以下是我尝试和实施罗素答案所做的工作。

首先我创建了几个整数变量:

var categoryfilter : Int! = 0
var lastcategoryfilter : Int! = 0

然后我创建了一些函数来保存和加载NSUserDefaults的值:

func LoadLastCategoryFilter()
{
    let defaults = NSUserDefaults.standardUserDefaults()
    lastcategoryfilter = defaults.integerForKey("ChosenCategory")
}


func SaveLastCategoryFilter()
{
    lastcategoryfilter = categoryfilter
    let defaults = NSUserDefaults.standardUserDefaults()
    defaults.setInteger(lastcategoryfilter, forKey: "ChosenCategory")
}

然后我使用按钮,以便用户可以设置变量的值并切换到游戏'屏幕:

@IBAction func buttonAstronomyCategory(sender: AnyObject) {

    categoryfilter = 1
    SaveLastCategoryFilter()
    ResetGameFromMainMenu()
    switchToMainGameScreen()
}



@IBAction fund buttonSportCategory(sender: AnyObject) {

    categoryfilter = 2
    SaveLastCategoryFilter()
    ResetGameFromMainMenu()
    switchToMainGameScreen()
}

等等每个类别。

在游戏界面中,我有一个加载lastcategoryfilter值的函数,然后按如下方式加载.json数据:

func LoadAllQuestionsAndAnswers()
{
    let path = NSBundle.mainBundle().pathForResource("content", ofType: "json")
    let jsonData : NSData = NSData(contentsOfFile: path!)!
    allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray


    if (lastcategoryfilter == 1)
    {
        let filteredEntries = allEntries.filter() {$0.category == "astronomy"}
        print(filteredEntries)

    }else{

        if (lastcategoryfilter == 2)
        {
            let filteredEntries = allEntries.filter() {$0.category == "sport"}
            print(filteredEntries)

        }else{
            if (lastcategoryfilter == 3)
            {
                let filteredEntries = allEntries.filter() {$0.category == "History"}
                print(filteredEntries)

            }else{

                if (lastcategoryfilter == 4)
                {
                    let filteredEntries = allEntries.filter() {$0.category == "Politics"}
                    print(filteredEntries)

                }else{

                    if (lastcategoryfilter == 5)
                    {
                        let filteredEntries = allEntries.filter() {$0.category == "Technology"}
                        print(filteredEntries)

                    }}}}}}

然后我使用与前面描述相同的功能来混淆/随机化问题并将其呈现给用户。

代码一切正常(即没有错误),但我的数据没有被过滤。

我不知道我哪里出错了,但我确定这只是一个愚蠢的新手错误!有什么建议吗?

2 个答案:

答案 0 :(得分:1)

过滤您的阵列很容易。这是一个相当人为的例子,它没有解决JSON或随机问题,但确实显示了过滤部分。显然,在你的例子中,你不会像我这里那样创建命名数组,但这个例子运行得很好。

struct QuestionStruct
{
    var id : Int
    var question : String
    var category : String
    var answer : String
}

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        var questions : [QuestionStruct] = []

        questions.append(QuestionStruct(id: 1, question:"question 1", category:"English", answer:"answer 1"))
        questions.append(QuestionStruct(id: 2, question:"question 2", category:"Physics", answer:"answer 2"))
        questions.append(QuestionStruct(id: 3, question:"question 3", category:"Physics", answer:"answer 3"))
        questions.append(QuestionStruct(id: 4, question:"question 4", category:"Maths", answer:"answer 4"))
        questions.append(QuestionStruct(id: 5, question:"question 5", category:"English", answer:"answer 5"))

        let filteredQuestionsPhysics = questions.filter() { $0.category == "Physics" }
        let filteredQuestionsEnglish = questions.filter() { $0.category == "English" }
        let filteredQuestionsMaths = questions.filter() { $0.category == "Maths" }
    }
}

更具体地说,在您的示例中,您可能希望修改LoadAllQuestionsAndAnswers以返回特定的问题列表而不是所有内容。此后,您可以像以前一样随机化它

func LoadAllQuestionsAndAnswers()
{
    let path = NSBundle.mainBundle().pathForResource("content", ofType: "json")
    let jsonData : NSData = NSData(contentsOfFile: path!)!
    allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
    //println(allEntries)
    let filteredEntries = allEntries.filter() {$0.category == categoryFilter}
    println(filteredEntries)
}

答案 1 :(得分:1)

确定Monomeeth - 我们可以采取一些措施来提高代码的可读性和可维护性。首先,我们可以删除所有嵌套的if语句,并使所有内容更加通用。

虽然你会有一系列按钮 - 你可以让他们都使用相同的方法,因为你每次都做同样的事情。如果将每个按钮的tag值设置为索引值,我们将知道哪个按钮将我们带到了该方法。如果您将categories存储在数组中,那么我们就不需要对Astronomy进行硬编码,我们只需使用categories[0]

以下是您需要的代码的关键部分

首先获得所有定义

class ViewController: UIViewController
{
    var categoryFilter : Int = 0
    var lastcategoryfilter : Int = 0

    let categories : [String] = ["Astronomy", "Sport", "History", "Politics", "Technology"] // if you have LOTS of these, you might want to load in a file and parse it ...
    var questions : [QuestionStruct] = [] // QuestionStruct is whatever structure you need to store the questions
    var filteredEntries : [QuestionStruct] = []

然后您需要一种方法来处理按下按钮,所有类别选择按钮都附加到

@IBAction func cmdSelectCategory(sender: AnyObject)
{
    // ALL of the buttons for select category are linked to this one method
    // the buttons have a tag value set to act as index

    categoryFilter = sender.tag
    generateFilteredQuestionSet()

}

然后您需要根据categoryFilter

过滤问题
func generateFilteredQuestionSet()
{
    filteredEntries = questions.filter() { $0.category == categories[categoryFilter]}
    print(filteredEntries)
}
祝你好运!