我是Swift和iOS开发的新手,我正在做一些在线课程。在一个课程中,我完成了一个iPhone测验应用程序。所有问题和潜在答案都是从.json文件中加载的,我们编写的代码会随机选择一个问题供用户回答。这种方法很好,但随着时间的推移,问题会重复出现,所以我一直在寻找防止这种情况的方法。
在尝试让应用程序存储随机选择并将其从剩余问题的整个池中删除之后,我意识到更有效的方法是最初将问题改组,然后逐个问问他们
所以,我做了一些挖掘并遇到了所谓的Fisher-Yates shuffle,并一直试图找到实现这一目标的方法。然后我找到了使用Swift的Gameplaykit中的GKRandomSource来改变事物的参考,所以我一直试图用它来做这个伎俩而且似乎无法让它发挥作用。
以下是我迄今为止在代码等方面尝试过的内容。
所有问题和潜在答案选择都存储在.json文件中:
{
"id" : "1",
"question": "Earth is a:",
"answers": [
"Planet",
"Meteor",
"Star",
"Asteroid"
],
"difficulty": "1"
}
我使用以下代码加载.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)
}
以下是我用来尝试实现所有问题的洗牌的代码:
var shuffledNumber : Int! = 0
loadAllQuestionsAndAnswers()
if #available(iOS 9.0, *) {
let shuffledNumber = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as NSArray as [AnyObject])
} else {
// Fallback on earlier versions
}
LoadQuestion(shuffledNumber)
我使用标签显示问题,并使用以下代码显示四个图像以显示潜在答案:
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)
let newSequence = indices.shuffle()
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()
}
最后,我使用以下代码在用户回答完问题后向其显示“下一步”按钮:
@IBAction func PressedButtonNext(sender: UIButton) {
print("button Next pressed")
if #available(iOS 9.0, *) {
_ = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
} else {
// Fallback on earlier versions
}
LoadQuestion(shuffledNumber)
现在,虽然我认为这一切都可行,但事实并非如此。当应用程序加载正常时,它总是向用户显示.json文件中的第一个问题,并在每次点击“下一步”按钮时不断重复相同的问题。
如何让这个问题随机播放所有问题,然后按顺序逐一询问?如果我需要包含更多代码,请告诉我。
答案 0 :(得分:1)
arrayByShufflingObjectsInArray
为您提供了一个洗牌的新数组。因此,您应该调用它一次,并在调用PressedButtonNext
时沿其移动索引。鉴于你已宣布
var shuffledNumber : Int! = 0
然后有效地重新宣布
let shuffledNumber = ...
它不起作用并不奇怪。我怀疑你没有在IOS 9下运行,所以你没有收到编译错误(虽然我之前没有使用#available)。
您应该声明以下实例变量:
var shuffledQuestions: [AnyObject]!
var nextQuestion = -1
然后在loadAllQuestionsAndAnswers
中,您应该包含
shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(...
并在PressedButtonNext
nextQuestion++
LoadQuestion(nextQuestion)
然后更改您的LoadQuestion以从洗牌后的问题中获取entry
:
let entry : NSDictionary = shuffledQuestions[index] as! NSDictionary
看一下这个例子here