Your first Bug & Connecting Outlets

Howe Wu
3 min readJun 11, 2022

紀錄在 raywenderlich 所上之課程。

老師提的 Bug 指的是 Bull’seye 在 App 剛開時,slider 預設位置是停在 50 ,但此時不滑 slider 直接按 button 的話 popup 跳出來的值卻是 0 這件事,

這個還蠻直覺的可以想到因為我們在 做 instance var ( 那個 var currentValue:Int = 0) 預設的值就是 0,所以解決的方法是要嘛進 Main storyboard 把 slider 的預設位置改成 0,要嘛就是將 currentValue:Int = 0 改成 currentValue:Int = 50 這樣。

下一堂課老師延伸那個 Bug 的問題,如果你沒有時常更新修改或者是 Project 有很多 view controller 要忙,很容易忘記把 code 的起始數值對 slider 的起始數值更新,因此這堂課是要來教對此有效的 fundamental technique,Connecting outlets.

So our goal here is to read the current value of the slider when the app begins.

老師先是示範一般我們可能就直接將
let roundValue = (slider.value.rounded())
currentValue = Int(roundValue)
這一段直接放進 viewDidLoad 裡面,因為這一段是 App 開啟時還未進入主要畫面時的一個迅速緩衝,在這裡放置 instance variables 是一個很好的選擇,只是放進來後一樣會有 error,而這個 error 跟之前的很類似,roundValue 在它的那個位置的 method 就已經結束了,所以在 viewDidLoad 時會找不到這個變數。

再來老師講到 Variable Scope 的觀念,共分為三個層級
Global scope
Instance scope
Local scope

First, there’s Global scope. These objects exist for the duraion of the app, and they’re accessible from anyway.
但老師沒有特別舉例 🤔

Second, there’s Instance scope. This is for variables such as your currentValue variable. These objects are alive for as long as the. object that owns them stays alive. In this case, the viewController owns currentValue, so as long as viewController is around, so is currentValue.
這樣跟 Global scope 的差別在哪 XD?

Finally, there’s Local scope. Objects with Local scope such as the slider parameter of sliderMoved, only exists for the duration of that method. As soon as the execution of the program leaves this method, local objects are no longer accessible.
舉例 Bull’seye 裡面的 message、alert、action 都是做在該 method 裡面,它們就都是 local scope,它們只會存在在 showAlert 被執行時,一旦結束後它們的暫存也會被清光。

這邊也提到 currentValue 幾乎是一直存在,應該是說只要 ViewController 一直開著 currentValue 就會一直存在著,因為它做在 ViewController 裡面。

Which in this case, is when the user terminates the app.
This type of variable is named an Instance variable, because its scope is the same as the scope of the object’s instance that it belongs to.

換句話說,如果想要某個特定的值能夠從這個動作到下一個動作就會需要使用 Instance variable。

接著老師回到 code,
If you think about what we’re trying to accomplish here,
指的是放進 viewDidLoad 裡面的
let roundValue = (slider.value.rounded())
currentValue = Int(roundValue)

we want to create an instance variable to store the slider, so we can access the slider’s value wherever we want.

在 ViewController 底下 創造一個 Instance variable
@IBOutlet ( because we need to connect the slider created in the storuboard to this variable. And whenever you wanna do that you have to preface it with a special keyboard IBOutlet. Kind of like how we did IBAction here for functions. )

接著老師繼續打

@IBOutlet weak ( 老師說之後的課程會講 weak 這是啥 ) var silder: UIslider! ( 驚嘆號也是說之後會講為什麼要加 )

接著要回 Main.storyboard 將 slider 點右鍵會出現一個 Referencing Outlets,它的下方有一個小選項 New Referencing Outlet,然後按住它右邊的小圈圈拖曳到 viewcontroller 會跳出剛剛做的 slider,將它們 connect 就可了。

這樣做就可以讓 slider 剛進 App 時,不滑 slider 直接點 button 會是顯示 slider 停的點的那個值也不用再手動去改 code。

最後再把 var currentValue:In = 50 的數字改成 0,因為 0 是一個很好代表 一個 Int 的初始值。

一開始有點不太懂明明就有一個 sliderMoved 了為何要在創造一個 Slider,回去看之前打的文章,

@IBAciotn func sliderMoved () {},

打到這裡時他說 : Except, it turns out when a function is called by a slider, it’s going to pass in the slider as a parameter. So we put slider as the name of the variable, that’s gonna be passed in , and a colon, and then we say UISlider, because UISlider is the type of the slider variable. And there’s one more thing. We have to put a underscore in front of it for this particular method.

然後長成這樣 : @IBAction func sliderMoved(_ slider: UISlider) {}

比照之前的 @IBAction func showAlert() {},我有很多疑問 XD,但目前只能先這樣學下去 XDD。

還是只有一點點的理解,sliderMoved 應該是滑動 slider 所獲得的數值,而這個數值也需要一個變數來儲存和獲取。
而 @IBOutlet weak var silder: UIslider! 這個的話是指在 “ 未滑動 slider 時 ”也能有個東西能存著 slider 的值,嗎?,

class ViewController: UIViewController {

var currentValue:Int = 0

@IBOutlet weak var slider: UISlider!

override func viewDidLoad() {

super.viewDidLoad()

let roundValue = (slider.value.rounded())

currentValue = Int(roundValue)

}

@IBAction func showAlert() {

let message = “The value of the slider is now \(currentValue)”

let alert = UIAlertController(title: “Hello, World!”, message: message, preferredStyle: .alert)

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

alert.addAction(action)

present(alert, animated: true, completion:nil )

}

@IBAction func sliderMoved(_ slider: UISlider) {

let roundValue = (slider.value.rounded())

currentValue = Int(roundValue)

}

}

目前為止有關 slider 延伸的疑問

@IBOutlet weak var slider: UISlider!
這一段放在那應該是要當作 instance variable 嗎? 驚嘆號的用意是什麼呢?

let roundValue = (slider.value.rounded())
currentValue = Int(roundValue)
這兩段為何只能放在 viewDidLoad 裡面?
放在最上方會出現 error

@IBAction func sliderMoved(_ slider: UISlider) {
為什麼要加底線 _ ?,不加的話一滑就會閃退

let roundValue = (slider.value.rounded())
一開始還沒有 @IBOutlet weak var slider: UISlider! 做 Instance variable 時
這一段的 slider 代表的是誰?

--

--

Howe Wu
0 Followers

一介調光師正努力轉生成 iOS 工程師