007 你的第一个 Bug

作者: ErlichLiu | 来源:发表于2017-10-04 19:11 被阅读10次

上一节

你的第一个 Bug


在这个 App 里其实有个小问题,你可能已经发现了,那么如何当这个问题再现的时候该怎么办呢?

  • 首先先按下暂停按钮来停止正在运行的这个 App,然后重新点击运行,不去拖动滑块,直接点击 Hit Me 按钮。这时,弹出来的提示信息是「The value of the slider is: 0」,但实际上滑块正处在中间的位置上(这是因为在我们设置 slider 的属性(Attribute)的时候默认值设置的为 50),所以我们期望的显式出来的数值也因该是 50。

练习:想一下为什么显式的值是 0,而不是 50?
答案:存储滑块数值的变量 currentValue 是在 sliderMoved() 方法里被赋值的,当你不移动滑块的时候,也就不会执行 sliderMoved() 方法,所以currentValue 的值只是被定义时候的 0,即 var currentValue: Int = 0

  • 所以修改默认的被定义时候的 currentValue 的值就好了,var currentValue:Int = 50

  • 验证一下吧,现在即便你不拖动滑块,直接点击按钮显式出来的值就是 50 啦。

让我们继续完善这个游戏吧


你已经构建好了 Interface Builder,也已经知道了如何获取和显式滑块的值。也花掉了几项 to-do list。还有一个要花时间做的事就是生成一个随机数当做拖动滑块的目标。首先要做的还是要提升关于滑块操作。

先试想这样一个问题,当你的滑动条的范围不是从 1 到 100 了,那在没有滑动滑块时候的取值也不会是 50 了。当你的项目越写越大,你要可能要在 ViewController 里关心数十个方法,很容易就会忘掉这些小的细节问题。所以我们要找一个更好的方法来处理滑块初始值的问题,几乎一劳永逸的解决问题。

于是我们在 ViewController.swift 中找到了这样一个方法 viewDidLoad() ,最初的时候它看起来是这样的:

override func viewDidLoad() { 
super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib.

}

当你创建一个基于 Xcode 模板的应用时,这段代码早就已经在你的源码中了。这个方法是干什么的呢?一旦 View Controller 开始加载用户界面,在你还没有看到界面样子的时候,这个方法就已经通过 UIKit 发送给它消息了。你可以简单地理解为,在你打开 App 但还没看到界面的时候,这个方法就已经执行了。刚好获取滑块的值既要及时又不需要让用户看到,所以在这里添加获取滑块当前值的代码再适合不过了,现在你要在这里面添加一些东代码。

override func viewDidLoad(){
super.viewDidLoad()
currentValue =  lroundf(slider.value)
}
  • 尝试点击运行 App , 你会发现出现了错误提示「Build Failed」,紧跟着有错误的提示:「Error:Use of unresovlved identifier slider」。

这个问题是因为在 viewDidLoad() 方法并不知道 slider是什么。那么问题来了,为甚 sliderMoved() 方法就没有出现这个问题呢?让我们再来看一眼 sliderMoved() 方法。

@IBAction func sliderMoved(_ slider: UISlider) { 
currentValue = lroundf(slider.value)
 }

在这里你做了同样的事情,采用了 lroundf() 方法,相当于采用四舍五入把slider.value这样一个浮点数转换成了整数。然后将这个数存入进currentValue这个变量中。这个为什么不在viewDidLoad()里还可以正常起作用呢?

不同之处在于 slider 是所谓sliderMoved()方法的参数。参数就是方法名称括号后面的内容,在这个案例里,就只有一个叫做 slider 的参数名称,它是一个 UISlider 类型的对象,可以接受 UISlider 对象发送过来的消息。

所以动作方法可以通过一个 UI 控制相关的参数,通过 UI 控件变化来触发方法。这也带来了一个便利性,当你想在方法中使用这个这个对象时,它就已经在那了。

所以当用户拖动滑块控件的时候,就会发生这一幕:UISlider 对象会说「 Hi ,view controller,我是 slider 对象,我刚刚被移动了,顺便说一下,这就是我的俩系方法,你可以在这得知关于我的一些消息」。

这里所谓的「联系方式」就是参数 slider 了。在你使用的时候 slider 就成了变量,在这里 slider 这个变量只能在这个方法内部用,换做术语来表达就是本地变量,也就意味着你不能在其他的地方使用这个 slider 变量。

本地变量
当我们初次提到变量概念的时候,讲到每个参数都有自己的声明周期,也就是它的范围。这个范围取决于你在程序的什么地方定义了这个变量。

在 Swift 里有三种可能的变量范围:

  • 全局变量:也就是这个变量的生命周期贯穿整个 App 的生命周期,你也可以在任何地方使用这个变量。
  • 实例变量:这就像 currentValue 一样,它的生命周期依赖它所属于的对象。
  • 本地变量:这个就像是 sliderMoved()方法的 slider 参数一样,它的生命周期只是存在于这个方法的运行时间。这个变量你也不可以应用在除此方法外的任何地方。

让我们来看一下 showAlert() 这个方法的上半部分:

@IBAction func showAlert() { 
let message = "The value of the slider is: \(currentValue)"

let alert = UIAlertController(title: "Hello, World", message: message, preferredStyle: .alert)

let action = UIAlertAction(title: "OK", style: .default, handler: nil) . . .

messagealertaction这样的变量都是在方法内被声明的,也只能用于这个方法内部,所以就是本地变量。一旦 showAlert()这个方法执行完毕,这些内部变量也就被销毁了。

而像 currentValue 这样的变量生命周期就长得多了,随着 ViewController 对象的消失而消失(本例中就是要等到用户终结掉此 App)。这也就是所谓的实例变量,换句话说,如果你想从一个操作到下一个操作保存一些数据,就可以使用实例变量了。就像你用 currentValue 保存滑块的值以便在下一个操作中使用一样。除此之外,为了解决刚才在viewDidLoad() 中的错误,我们要采用一个特殊类型的实例变量——outlet。

添加以下代码到 ViewController.swift

@IBOutlet weak var slider: UISlider!

这一行代码在哪里其实并不是非常重要,只要把它放在 ViewController 类里就行了。我的习惯是通常会把 outlet 类型的变量跟实例变量放在一起。

这一行代码告诉 Interface Builder 你有一个和 UISlider 对象连接的名叫 slider 的变量。就像 Interface Builder 调用方法一样,它调用这些变量的出口。Interface Builder 只能看到标记 @IBOutlet 的变量。

现在切不着急理解 weak 和 感叹号的含义,我们将会在下一个教程理解是这些的必要性。现阶段只要记住声明 outlet 变量的格式是 @IBOutlet weak var ... !

  • 打开 storyboard,按住 Ctrl 并单击 slider,先不需要拖拽到任何地方,松开鼠标,会弹出来一个 slider 的连接窗口。这个窗口和 Connection inspector 一样,我只是告诉你另一个代替的操作方法。
  • 点击 New Referencing Outlet 的空心圆,然后拖动到 View Controller
  • 然后在弹出来的窗口中选择 slider

你现在已经成功将 storyboard 的 slider 和 view controller 的 slider 使用 outlet 连接起来了。

现在所有的设置都完成了,你可以在 view controller 里随心的使用 slider 变量并获取到它的准确值了。

  • 在 Interface Builder 里修改 slider 的初始值,然后重新运行 App ,这时你看到的就不是 50 啦。

你可能早就注意到了那些以 // 开始的一行绿色的代码,也有 /*...*/ 的一段都是绿色的代码。这就是注释啦,注释本身并不会被执行,通常注释是来起到解释作用的,解释一些方法的作用和参数,解释一些难以理解的代码的意图,注释最大的目的是为了自己和他人在日后的代码修复优化的过程中更加容易理解当时代码的含义。

快复习一下这一章节讲的内容吧,这一节数字稍微有点多,下一节我们会解决另一个 to-do list 的一个大事,如何生成随机数以及更多对于游戏的优化。

下一节

相关文章

  • 班训营第一次作业

    8组组长|张海英|007-490 第一次作业第一个问题:写下你母班的bug,这些bug为什么没有被修复?你有什么建...

  • 007 你的第一个 Bug

    上一节 你的第一个 Bug 在这个 App 里其实有个小问题,你可能已经发现了,那么如何当这个问题再现的时候该怎么...

  • 可能我们都被局限了?

    参加第三期007写作团队班训营,明星校长给我们第一节课出了两个问题。 第一个问题:写下你的母班的bug,这些bu...

  • iOS(OC)开发之个人调试技巧分享

    开篇小故事:bug的由来 从电脑诞生之日起,就有了电脑BUG。第一个有记载的bug是美国海军的编程员,编译器的发明...

  • 华为 Mate 20 BUG,IHG升白金只需5晚

    前几天拼多多BUG事件闹得沸沸扬扬,一晚上损失了几千万,2019年第一个BUG拼多多是没跑了。 说到BUG,这里还...

  • 扔出去的钱,能不能捡回来——加入付费社群的体会

    今天说说加入007写作群的感受。 要点速读 007写作群的玩法是脑洞大开的赚钱方式 它的第一个价值是在为你的写作行...

  • 软件 bug 的生命周期

    从发现软件故障到解决它们,这里讲述是开发团队如何压制软件 bug。 1947 年,发现了第一个计算机 bug ——...

  • 七个远方的第二站,你们去吗?

    去年5月,我还没有加入007,我男朋友那时加入007半年多,对于007正值狂热,看到第一个远方,敦煌站,那是非去不...

  • 6-13 监听播放事件完善音乐播放

    bug1 时间播放还是有很多bug的。先看第一个: 点击自定义开关,开启和关闭,总控开关是能够相应地开启关闭的。但...

  • 做值月生的收获

    4月21号在深圳线下面基明星校长(007第一个值月生)苏磊班长(007链接王)千哥(007er之家舵主)菜菜(34...

网友评论

    本文标题:007 你的第一个 Bug

    本文链接:https://www.haomeiwen.com/subject/inmcyxtx.html