ios - Swift:检查存储在 NSMutableArray 值中的 JSON 值

标签 ios json swift

我无法检查用户是否已经看到 JSON 文件中的问题。

我有一个 NSArray (allEntries),其值中包含存储的 JSON。我这样创建:

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

如果我打印出值之一 allEntries[0],我得到:

{
answers =     (
    Chimney,
    "Front door",
    Window,
    "Dog door"
);
difficulty = 1;
id = 2;
question = "How does Santa get into a house on Christmas eve?";
}

现在,稍后在我的代码中我只需要随机调用其中一个问题,所以我生成一个索引并将其传递给此函数:

func LoadQuestion(index : Int)
{
    let entry : NSDictionary = allEntries.objectAtIndex(index) as! NSDictionary
    let questionID : Int = entry.objectForKey("id") as! Int
    let question : NSString = entry.objectForKey("question") as! NSString
    let arr : NSMutableArray = entry.objectForKey("answers") as! NSMutableArray

    ....
}

加载问题时。我将该 ID 值添加到另一个名为 alreadyAsked

的数组中

起初我得到这个错误:

Could not cast value of type '__NSCFString' (0x865ee0) to 'NSNumber' (0x133781c).

在这一行:

let questionID : Int = entry.objectForKey("id") as! Int

所以我将 Int 更改为 NSString:

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

然后尝试像这样重铸:

let questionID = Int(questionIDRaw as! Int)

但后来我遇到了这个问题:

Definition conflicts with previous value

我需要发生的事情:

免责声明 我是菜鸟。到目前为止,我已经按照 Udemy 的教程进行操作,并设法让该应用程序正常运行。额外的检查是我正在尝试做的事情。

因此,我希望能够检查以确保当我提出一个随机问题时,该问题的 ID(在 json 中)不在 alreadyAsked 数组中。我该怎么做?

感谢所有帮助:)

编辑:

完全 Controller :

import UIKit
import AVFoundation // audio


class ViewController: UIViewController {

@IBOutlet weak var buttonA: UIButton!
@IBOutlet weak var buttonB: UIButton!
@IBOutlet weak var buttonC: UIButton!
@IBOutlet weak var buttonD: UIButton!


@IBOutlet weak var labelQuestion: UILabel!

@IBOutlet weak var labelScore: UILabel!

@IBOutlet weak var labelFeedback: UILabel!

@IBOutlet weak var buttonNext: UIButton!

@IBOutlet weak var BackgroundImageView: UIImageView!

var score :Int! = 0
var allEntries : NSArray!


var currentCorrectAnswerIndex : Int = 0

var audioPlayer = AVAudioPlayer()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    
    LoadAllQuestionsAndAnswers()
    
    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
    LoadQuestion(randomNumber)
    LoadScore()
    
    AdjustInterface()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


func LoadScore()
{
   let defaults = NSUserDefaults.standardUserDefaults()
    score = defaults.integerForKey("score")
    labelScore.text = "score: \(score)"
}


func SaveScore()
{
    let defaults = NSUserDefaults.standardUserDefaults()
    defaults.setInteger(score, forKey: "score")
}


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)
    
}


func LoadQuestion(index : Int)
{
    let entry : NSDictionary = allEntries.objectAtIndex(index) as! NSDictionary
    let question : NSString = entry.objectForKey("question") as! NSString
    let arr : NSMutableArray = entry.objectForKey("answers") as! NSMutableArray
    
    //println(question)
    //println(arr)
    
    labelQuestion.text = question as String
    
    let indices : [Int] = [0,1,2,3]
    let newSequence = shuffle(indices)
    var i : Int = 0
    for(i = 0; i < newSequence.count; i++)
    {
        let index = newSequence[i]
        if(index == 0)
        {
            // we need to store the correct answer index
            currentCorrectAnswerIndex =  i
            
        }
        
        let answer = arr.objectAtIndex(index) as! NSString
        switch(i)
        {
        case 0:
            buttonA.setTitle(answer as String, forState: UIControlState.Normal)
            break;
            
        case 1:
            buttonB.setTitle(answer as String, forState: UIControlState.Normal)
            break;
            
        case 2:
            buttonC.setTitle(answer as String, forState: UIControlState.Normal)
            break;
            
        case 3:
            buttonD.setTitle(answer as String, forState: UIControlState.Normal)
            break;
            
        default:
            break;
        }
        
        
        
    }
    buttonNext.hidden = true
    // we will need to reset the buttons to reenable them
    ResetAnswerButtons()
    
}

func shuffle<C: MutableCollectionType where C.Index == Int>(var list: C) -> C {
    let total = list.count
    for i in 0..<(total - 1) {
        let j = Int(arc4random_uniform(UInt32(total - i))) + i
        swap(&list[i], &list[j])
    }
    return list
}

func ResetAnswerButtons()
{
    buttonA.alpha = 1.0
    buttonB.alpha = 1.0
    buttonC.alpha = 1.0
    buttonD.alpha = 1.0
    buttonA.enabled = true
    buttonB.enabled = true
    buttonC.enabled = true
    buttonD.enabled = true
}


@IBAction func PressedButtonA(sender: UIButton) {
    print("button A pressed")
    buttonB.alpha = 0.3
    buttonC.alpha = 0.3
    buttonD.alpha = 0.3
    
    buttonA.enabled = false
    buttonB.enabled = false
    buttonC.enabled = false
    buttonD.enabled = false
     CheckAnswer(0)
}

@IBAction func PressedButtonB(sender: UIButton) {
    print("button B pressed")
    buttonA.alpha = 0.3
    buttonC.alpha = 0.3
    buttonD.alpha = 0.3
    
    buttonA.enabled = false
    buttonB.enabled = false
    buttonC.enabled = false
    buttonD.enabled = false
    CheckAnswer(1)
}

@IBAction func PressedButtonC(sender: UIButton) {
    print("button C pressed")
    buttonA.alpha = 0.3
    buttonB.alpha = 0.3
    buttonD.alpha = 0.3
    
    buttonA.enabled = false
    buttonB.enabled = false
    buttonC.enabled = false
    buttonD.enabled = false
    CheckAnswer(2)
}

@IBAction func PressedButtonD(sender: UIButton) {
    print("button D pressed")
    buttonA.alpha = 0.3
    buttonB.alpha = 0.3
    buttonC.alpha = 0.3
    
    buttonA.enabled = false
    buttonB.enabled = false
    buttonC.enabled = false
    buttonD.enabled = false
    CheckAnswer(3)
}

@IBAction func PressedButtonNext(sender: UIButton) {
    print("button Next pressed")
    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
    LoadQuestion(randomNumber)
    // we need to play a sound effect for the next question coming
    PlaySoundButton()
    
}

func CheckAnswer( answerNumber : Int)
{
    if(answerNumber == currentCorrectAnswerIndex)
    {
        // we have the correct answer
        labelFeedback.text = "Correct! +1"
        labelFeedback.textColor = UIColor.greenColor()
        score = score + 1
        labelScore.text = "score: \(score)"
        SaveScore()
        // later we want to play a "correct" sound effect
        PlaySoundCorrect()
        
    }
    else
    {
        // we have the wrong answer
        labelFeedback.text = "Wrong answer"
        labelFeedback.textColor = UIColor.redColor()
        // we want to play a "incorrect" sound effect
        PlaySoundWrong()
    }
    
    buttonNext.enabled = true
    buttonNext.hidden = false
}

func PlaySoundCorrect()
{
   let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("correct", ofType: "mp3")!)
    
    let error:NSError?
    do {
        audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
    } catch let error1 as NSError {
        error = error1
        print(error)
    }
    audioPlayer.prepareToPlay()
    audioPlayer.play()
    
    
}

func PlaySoundWrong()
{
    let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("wrong", ofType: "wav")!)
    
    var error:NSError?
    do {
        audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
    } catch let error1 as NSError {
        error = error1
        print(error)
    }
    audioPlayer.prepareToPlay()
    audioPlayer.play()
}


func PlaySoundButton()
{
    let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("button", ofType: "wav")!)
    
    let error:NSError?
    do {
        audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
    } catch let error1 as NSError {
        error = error1
        print(error)
    }
    audioPlayer.prepareToPlay()
    audioPlayer.play()
}


func AdjustInterface()
{
    let screenSize: CGRect = UIScreen.mainScreen().bounds
    let screenWidth = screenSize.width
    let screenHeight = screenSize.height
    
    buttonA.center = CGPointMake(screenWidth / 2, buttonA.center.y)
    buttonB.center = CGPointMake(screenWidth / 2, buttonB.center.y)
    buttonC.center = CGPointMake(screenWidth / 2, buttonC.center.y)
    buttonD.center = CGPointMake(screenWidth / 2, buttonD.center.y)
    buttonNext.center = CGPointMake(screenWidth / 2, buttonNext.center.y)
    labelQuestion.center = CGPointMake(screenWidth / 2, labelQuestion.center.y)
    
    BackgroundImageView.frame = CGRectMake(0, 0, screenWidth, screenHeight)
    
    
}

}

在我开始尝试检查问题是否已被查看之前,这个 View Controller 是完整的。所以,澄清一下,在上面的 View Controller 中,我如何:

  • 从问题中的 JSON 条目中获取 ID
  • 将其存储在名为 alreadyAsked 的数组中
  • 检查加载的问题是否已经看过。如果是这样,请跳过并选择另一个
  • 如果所有的问题都被看到了,在控制台中显示 none left to view

最佳答案

  • 从问题中的 JSON 条目中获取 ID

有什么理由需要在 Int 中包含 ID 吗? 如果不是,请将您的 questionID 保留为字符串。

let questionID = entry["id"] as! String

(如果是,你可以这样做,但我省略了这种情况。)

        let questionID = Int(entry["id"] as! String)!

(假设您的“content.json”从不包含意外值...)

  • 将其存储在一个名为 alreadyAsked 的数组中

将实例属性声明为:

    var alreadyAsked: Set<String> = []

并将 questionID 附加为:

        alreadyAsked.insert(questionID)

(我希望你知道你需要把这条线放在哪里。)

  • 检查加载的问题是否已经看过。如果是这样,请跳过并选择另一个

您可以在代码中到处检查它,但一个可能的地方是在 LoadQuestion(_:) 方法中。

您可能需要返回一个值,表明该问题已经被问过:

    func loadQuestion(index : Int) -> Bool

(您最好遵循一个简单的命名准则:仅对类型使用大驼峰式命名。这样可以提高共享时代码的可读性。我的意思是“共享”包括在问答网站。)

在你得到那个 questionID 之后,检查它:

        if alreadyAsked.contains(questionID) {
            return false //already asked, so not again
        }

您需要在 loadQuestion(_:) 的末尾放置 return true

您可能需要重复直到 loadQuestion(_:) 返回 true。

        var randomNumber: Int
        repeat {
            randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
        } while !loadQuestion(randomNumber)

(这不是有效的,但实际上(“看似”会更合适?)它有效。并信守 promise “如果是这样,跳过并选择另一个”)

  • 如果所有的问题都被看到了,在控制台中显示 none left to view

在进入上面的循环之前检查它:

        if allEntries.count > alreadyAsked.count {
            var randomNumber: Int
            repeat {
                randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
            } while !loadQuestion(randomNumber)
            loadScore()

            adjustInterface()
        } else {
            //display in console none left to view
            //...
        }

您的代码有很多部分不安全或有问题,其中一些可能很关键。如果您自己无法解决问题,您可以发布另一个问题。

关于ios - Swift:检查存储在 NSMutableArray 值中的 JSON 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38884093/

相关文章:

ios - Swift - 以模态方式打开 WebView 链接

php - 从mysql输出json指定数据

php - 在 for 循环中将两个条目粘在一起

ios - 从另一个类更改按钮的状态

ios - 如何检测 iOS 设备上的耳机(扬声器)可用性?

iphone - 我怎样才能捕捉到 MapView 上的点击,然后将它传递给默认的手势识别器?

ios - 如何使用 Flutter 打开 iPhone 上的默认电子邮件应用程序?

ios - 无法符号化崩溃报告

php - 创建新的jstree节点后如何设置id?

ios - Swift - 从解析中接收图像并显示它们时出现问题