IOS 入门(基于 IOS Apprentice 的真正面向零基础的完整解决的方案)

008 生成随机数

2017-10-09  本文已影响19人  ErlichLiu

上一节

生成随机数


让我们继续完成列表中下一个待办事项:生成一个随机数,并让它显示在屏幕上

生成随机数的目的就是为了让游戏有更多的不确定性,随机生成一个目标数,然后让玩家向着这个目标数来滑动滑块。这里会涉及到一个生成随机数的方法arc4random_uniform()

首先在游戏开始前生成一个随机数无疑是最好的方式,所以在ViewController.swiftviewDidLoad()中添加以下代码。

targetValue = 1 + Int(arc4random_uniform(100))

目前整个viewDidLoad() 方法看起来是这样的:

override func viewDidLoad() { 
super.viewDidLoad() 
currentValue = lroundf(slider.value)
targetValue = 1 + Int(arc4random_uniform(100)) 
}

这段代码里你都做了什么?你使用了一个新的变量targetValue,实际上你却并没有声明这个变量,不过一会你就要去定义一个变量了。你还使用了arc4random_uniform()方法生成了一个从 0-100 的随机数。关于 1-100 的范围还是要解释一下,你通过arc4random_uniform()能生成的最大的随机数就是99,而我们的游戏是有 100 这个值的,所以我们在arc4random_uniform()的基础上 +1。

然而你必须要声明 targetValue 这个变量,因为在后面需要将 targetValue 和拖动滑块所得的值相比较,而不定义变量 targetValue 的话,在后面比较的过程中 Xcode 则不会知道目标值。

所以还要在ViewController.swift 中添加以下代码,声明targetValue变量。

var targetValue: Int = 0

在声明变量的时候,一定要有一个值,你刚刚声明变量的初始值就是 0 。而这个初始值 0 则永远不会被使用,因为这个值会在 viewDidLoad() 中被 arc4random_uniform() 方法重写过。

注意
由于 Xcode 有实时纠错,所以在你还没有完成一个语句或者一个逻辑操作的时候,Xcode 会暂时的提示你关于错误的信息,不用担心,当你完成后它就会自动消失了,如果没有消失的话,那可能意味着你真的有错误了……

下面就涉及到计算的问题了,你已经在viewDidLoad()方法中生成了随机数,并保存到了变量中,当你点击 Hit Me 按钮的时候也同时在变量中保存了滑块值。然后将这两个值拿到 showAlert()中进行比较并显式。

@IBAction func showAlert() {

let message = "The value of the slider is: \(currentValue)" + "\nThe target value is: \(targetValue)"

let alert = . . .

}

当你看到三个点构成的省略号...的时候,意味着在这以后的内容均相同,这可以让整个教程更加的精简。

在这一步我们只是添加了一小段话,让 targetValue 的值显示出来。

注意
在前面你用了加号(+)将两个不同长度的字符串连接成一组字符串。Swift 允许用户使用加号操作不同的字符,加号所做的操作效果则取决于你涉及到的数据类型,如果是两个 Int 类型的数,Swift 做的就是数学运算,如果是两个 String(字符串)的类型,就是将两个字符串连接起来。

为游戏添加轮次功能


不知道你是否已经注意到了这个问题,当你再点几次 Hit Me 按钮,弹出来的随机数都是同一个数字。原因在于生成随机数的方法在viewDidLoad()方法中,而viewDidLoad()方法只在加载页面时候执行一次。

所以经过我们的实际尝试发现,to-do list 中的关于随机数的表述其实应该是:在每个轮次即每次点击 Hit Me 按钮的时候就该生成一个新的随机数。

我所谓的轮次就是期初开始分数是 0 ,轮次就是 1 ,当时预设的 slider 的值是 50 ,然后等着玩家按 Hit Me 按钮,这时候这个轮次就结束了。

然后去计算每个轮次的分数到总分数,然后依次增加轮次数,并开始下一次轮次。

想要计算轮次,我们需要一个计算轮次的方法,所以在ViewController.swift中添加以下方法:

func startNewRound() {
targetValue = 1 + Int(arc4random_uniform(100)) 
currentValue = 50 
slider.value = Float(currentValue) 
}

你可以把它放在只要在类的花括号内就可以,这个方法跟之前没啥大区别,主要是你设置了新一个轮次的参数设置,一样要生成一个随机数,然后设置好滑块的初始位置为 50。

本身这个方法的内容和 viewDidLoad()方法中的内容就是重复的,所以我们让viewDidLoad()方法直接调用startNewRound()就 OK 啦,这样可以让代码更加精简,修改完的代码如下所示:

override func viewDidLoad() {
super.viewDidLoad() 
startNewRound() 
}

你当然也需要在点击完 Hit Me 后调用 startNewRound()

@IBAction func showAlert() { 
. . .
startNewRound()
}

在本方法最后(present...后)调用startNewRound()方法。

现在这个过程就已经完成了,无论是游戏的开局调用viewDidLoad()还是点击 Hit Me 调用的showAlert()都会让这个游戏正常运行,整个过程也就是我们之前称之为的「事件驱动」。

可能你会看到这样的代码句:

  self.startNewRound()

这跟刚才的前面没有 self的效果一样,还是会发消息给 view controller 自己。

通常我们会这样调用一个对象的方法:

reciver.methodName(parameters)

receiver就是你要发消息的对象,如果你想发消息给自己,那么receiver 就是 self,但是发消息给自己实在是太平常了,一般我们就省略掉 self这个词。

继续讲关于 showAlert()方法,理性的来讲,这不是你第一次调用 addAction()方法,它是 UIAlertController中的一个方法,而present()view controller 中的一个方法。

当你写 Swift 程序的时候,很大一部分内容就是在调用方法。

我希望你能理解「new round」模式在自己方法中的优势,如果你没有理解透彻,我们来看 viewDidLoad()showAlert()的方法代码结构如下:

override func viewDidLoad() { 

super.viewDidLoad()
targetValue = 1 + Int(arc4random_uniform(100)) 
currentValue = 50 
slider.value = Float(currentValue)
}

@IBAction func showAlert() {
 . . .
targetValue = 1 + Int(arc4random_uniform(100)) 
currentValue = 50 
slider.value = Float(currentValue)
}

你能在这段代码中看到什么?同样的一段代码被两个地方完全的复用了,当然,虽只有三行,但是在真正的代码中你面临的情况可能要多得多。而且当你的逻辑变的时候,你就要同时修改两个地方。如果这些代码是你刚刚写过,那可能你还能记得住,但是往往我们修改的时候可能都是几个星期后了,经常会对每个方法里的重复代码修改发生遗忘的现象。所以赋值长段的代码是经常容易产生 bug 的地方。这时候我们就需要将重复的代码用一个新的方法代替。起一个相关度比较高的名字,当你一瞥的时候就知道这个方法是干什么的了。但你可能不能一瞥就知道下面代码的含义:

targetValue = 1 + Int(arc4random_uniform(100))
currentValue = 50 
slider.value = Float(currentValue)

按照你的逻辑,你可能会这样想:先生成一个随机数,然后重置 slider 的位置,所以,这可能是一个下一轮的功能。如果用下面的一个方法来代替就会更加的清晰啦:

startNewRound()

所以对于善用方法的优势一目了然了吧。

你也应该注意到,每个轮次开始的时候,slider 的位置都是被重置过的。这是因为在 startNewRound()方法中设置了 currentVlaue为50,设置 slider 的位置跟读取 slider 的位置正好是相反的过程。

在赋值的过程中要注意,因为 slider.value是 Float (浮点) 类型,而currentValue的值是 Int 类型,Int 类型是不能直接赋值给 Float 类型的,所以要在赋值的时候有个转化的过程:

slider.value = Float(currentValue)

Swift 在数据类型上要比一般的编程语言都要严格,这对初学者来说并不友好,除此之外,Xcode 的编译器对于错误的提示往往也不够明确。但是记住,一般遇到像这样的错误提示「cannot assign value of type 'something' to type 'something eles'」就说明你可能在两者的数据类型上产生了冲突,解决方法就是将一个变量的数据类型转换为另一个变量的数据类型。

赶快回顾一下我们这一节讲了什么吧。

下一节我们将讲述如何将随机数生成的目标值放在 Label 上展示给用户。

上一篇下一篇

猜你喜欢

热点阅读