我們已經在編程的世界轉了一大圈了,開始著手完成這個游戲吧
你已經建造了用戶界面,并且你知道如何讀取滑條位置上的值。已經搞定了工作清單上的不少項目了。
剩下最大的項目就是生成一個隨機值作為目標并且計算玩家的得分。但是首先,需要先對滑條做出一些改進。
輸出(outlet)
你設法存儲了滑條的值到一個變量里并且在提醒窗口里展示它。這非常不錯,但是還需要進行一點改進。
如果你想要給storyboard里的滑條(slider)設置一個新的初始值,不是50的,1-100之間的另一個值會怎么樣?接下來currentValue又會出問題因為app認為它開始時總是50。你得記得同時給currentValue一個同樣的新的初始值才行。
對我而言,這些小事情根本就記不住,特別是當工程逐漸擴大并且你有十幾個視圖控制器(view controller)要照顧的時候,或者你幾周沒有來看這些代碼的時候,這種小事特別容易忘掉。
因此,為了一次性徹底解決問題,你要在ViewController.swift里的viewDidLoad()方法里做些工作。這個方法眼下看起來是這個樣子的:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
當你基于Xcode模版建立這個工程的時候,Xcode早已經在源代碼里放置了一個viewDidLoad()方法。你現在需要添加些東西進去。
當view controller一從storyboard文件中讀取用戶界面時(就是界面已經加載好了,但是還沒有展現到屏幕上的前一刻),就會由UIKit向viewDidLoad()發送消息。在這一時刻,用戶界面還不可見,所以這是一個理想的地方用于設置變量的初始值。
把viewDidLoad()改成下面這個樣子:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
currentValue = lroundf(slider.value)
}
這個意圖是無論你在storyboard里設置滑條的初始值為任何值,都同使用這個值去初始化變量currentValue的值。
回憶一下你需要對這個數取整,因為currentValue是一個Int(整數)型的,整數不能在小數點后有值。
不幸的是,當你做完這一變更運行app時,Xcode開始大發牢騷。自己試一試。
試著運行app
Xcode會在類似于“Error:Use of unresolved identifier ‘slider’”這樣一句話后面告訴你“Bulid Failed”
會這樣是因為viewDidLoad()并不知道slider這個名字。
但是為什么sliderMoved()就輕松的知道了?讓我們再來看一看這個方法:
@IBAction func sliderMoved(_ slider: UISlider) {
currentValue = lroundf(slider.value)
}
在這里你做了同樣的事情,對slider.value進行取整并且放入currentValue里。所以為什么同樣的辦法在viewDidLoad()里就不行了呢?
區別在于slider是一個sliderMoved()方法中所謂的參數。參數就是方法名稱后括號里面的東西。目前這里僅有一個參數叫做slider,用于指代UISlider對象發送消息的動作方法(Action Method)。
動作方法可以有一個參數用于指代控件(UI Control)觸發的方法。這對你在方法中使用這個對象是非常便利的,就像你在sliderMoved()里做的那樣(這里談論的對象就是UISlider)。
當用戶移動滑條時,UISlider對象基本上就是在說:“嗨,view controller,我是一個滑條對象,我剛才移動了,順便說下,這是我的電話號碼,你可以用它聯系我(這個電話號碼就是參數slider)”
這個電話號碼(slider)僅僅在sliderMoved()這個特定方法中有效。
換句話說,slider是局部的,你無法在任何其他地方使用它。
局部變量
當我初次介紹變量時,我提到了每個變量都有明確的壽命,也叫作用范圍。變量的作用范圍依賴于你是在程序的什么位置定義它的。
以下是Swift中的三種作用范圍級別:
1、全局作用范圍(Global scope),這些對象只要app運行它們就存在,直到用戶關閉app,并且可以在任何地方訪問。
2、實例作用范圍(Instance scope),像currentValue這種變量就是。這些對象只要它們的屬主還存在,它們就一直存在。
3、局部作用范圍(local scope),具有局部作用的對象,比如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)
......
因為messgae,alert,action都是在方法內部創建的,所以它們是局部的。僅當showAlert()方法被執行時它們才存在并且當方法執行結束后它們就不存在了。
一旦showAlert()執行完畢,其中再沒有語句需要執行的時候,電腦就摧毀了message、alert、action。它們的存儲空間也不復存在。
而變量currentValue則永遠會存在,或者說至少ViewController存在它就存在,直到用戶關閉app(因為到目前為止我們的app也只有一個ViewController,所以只要app還在運行,currentValue就存在)。這種類型的變量就叫做實例變量,因為它們的作用范圍和其所屬對象的實例是一樣的。
換句話說,如果你想從一個動作事件到另一個的時候保存某個值,你就要使用實例變量。
解決我們剛才那個報錯的方法就是用一個新的實例變量存儲slider,就像currentValue那種,除了此時數據類型不是Int(整數)。并且你不能使用標準實例變量,而是用一種比較特殊的,名為輸出(outlet)那種。
把下面這行添加到ViewController.swift:
@IBOutlet weak var slider: UISlider!
這一行添加在哪里并不重要,只要是在class ViewController后面的花括號里面就行。我經常把outlets和其他實例變量放在一起。
這一行告訴界面建造器現在你擁有了一個叫做slider的變量,它可以和UISlider對象鏈接起來。就像界面建造器調用動作方法一樣,可以調用這些outlets。除了這些以@IBOutlet開頭的東西以外,界面建造器看不到任何其他變量。
目前先不要操心關鍵字weak和那個感嘆號,為什么必須要它們我們會在下一個課程中講到。目前僅僅記住用于outlet的變量必須用@IBOutlet weak聲明并且末尾要有一個感嘆號就可以了(有時候會是一個問號,這些把戲都會在合適的時候給大家講到)。
打開storyboard。按住ctrl并且點擊一下滑條,不要拖,點擊一下就好(或者可以用鼠標右鍵點擊一下滑條),你會看到彈出一個菜單,上面有所有關于滑條的鏈接情況。
這個彈出菜單和鏈接檢查器的作用是一樣的。我只是想給你展示一下多種方法。
點擊New Referencing Outlet傍邊的空心圓圈把它拖拽到View Controller(黃色圖標的那個)上:
拖到View Controller后會彈出一個小菜單,上面有slider和view,選擇slider。
這就是你剛添加到對象上的鏈接。你已經成功的完成了從storyboard到view controller的滑條輸出之間的滑條對象的鏈接。
現在你已經完成了全部的設置工作,你可以使用slider變量在view controller的內部任何地方引用滑條對象。
有了這些改進,你就可以在界面建造器中任意的設置滑條的初始值了。當app開始運行,currentValue會被設置為相應的值。
運行app并且直接點擊Hit Me。它會顯示出:“The value of slider is:50”。然后停止app,在界面建造器中將滑條的初始值設定為25,然后再運行app,還是不要動滑條,直接點擊Hit Me。彈出窗口上的值現在就會顯示為25.
測試結束后,將滑條的初始值還原為50.
練習:把currentValue的值重新設置為0.再運行app,看看會發生什么。你會發現currentValue的初始值已經不重要了,因為viewDidLoad()會把currentValue的值覆蓋一遍。但是你不能把這一行刪掉,因為swift要求所有變量都必須有一個值,所以就讓他初始化為0吧。
注釋(Comments)
你應該見過幾次那種綠色的以//開頭的句子了。這些就是注釋語句。你可以在//符號后面寫上你想寫的任何文字,編譯器是完全忽視它們的。
// I am a comment! You can type anything here.
任何位于/*與*/之間的語句也被視為注釋。//和/* */的區別是//后面必須是單行,而/* */之間可以有多行。
/*
I am a comment as well!
I can span multiple lines
*/
多行注釋經常用于失效大段的代碼,你在尋找一個bug的時候,經常會把大段的代碼先失效掉。
注釋最大的用處就是用于解釋你的代碼工作原理。書寫良好的代碼是無須加以解釋的,但是添加一些注釋說明的幫助會非常大。
給誰解釋?基本上就是給你自己呀!
除非你的腦容量和大象的體積一樣,否則當你六個月以后回來看自己的代碼的時候你基本不會記得這是什么。使用注釋可以有效節約你的腦容量。
如你所見,Xcode會自動在代碼文件的頂部添加版權相關的信息。就問個人而言,我不太關心這些版權說明。如果你不喜歡它們,就趕緊刪掉吧。
生成隨機數
在這個游戲可以玩之前,你還有一段路要走,所以,讓我們開始清單上的下一個項目吧:生成一個隨機數,并且把它顯示到屏幕上。
在制作游戲時隨機數經常出現因為游戲經常需要一些無法預測的場景。你不可能有一臺電腦可以生成真實的無法預測的隨機數,但是你可以采用一種叫做偽隨機數的方法生成一系列數字。你會使用到我最喜歡的這個函數arc4random_uniform()。
最佳的生成隨機數的時機是在游戲一開始的時候。
將下面這行代碼添加到ViewController.swift的viewDidLoad()中:
tragetValue = 1 + Int(acr4random_uniform(100))
完成后viewDidLoad()應該是這個樣子的:
override func viewDidLoad() {
super.viewDidLoad()
currentValue = lroundf(slider.value)
tragetValue = 1 + Int(acr4random_uniform(100))
}
這里是做了什么?首先,你使用了一個新的變量,tragetValue。你目前還沒有實際的定義這個變量,你會在幾分鐘后去做這件事。
你同時也調用了acr4random_uniform()這個函數用于交付一個1到100之間的隨機整數。
實際上,你得到的最大的整數是99,因為acr4random_uniform(100)生成的范圍是0到99,為了得到1到100之間的整數,我們需要加上一個1。
你還需要在view controller中聲明tragetValue這個變量,否則的話Xcode會向你抱怨它從沒見過這個變量。
如果你沒有告訴編譯器變量targetValue的類型,那么編譯器將不知道應該分配多少存儲空間給它,也不能核實你是否可以在其他地方使用這個變量。
在ViewController.swift的頂部添加這個變量,和其他變量放在一起:
var tragetValue: Int = 0
Swift中的變量必須有一個值,所以我們給這個變量了一個初始值0。這個0永遠不會在這個游戲中被實際使用;它總是會被viewDidLoad()中的隨機數覆蓋掉。
??:直到你添加上面那條語句為止,Xcode應該會指出它不認識tragetValue這個變量。而你添加了剛才那條語句后,這個報錯消息就應該消失了。
Xcode會努力的在分析程序錯誤這方面提供幫助。有時,在你沒有完全敲完代碼時,你會看到不斷出現和消失的報錯信息。
不要被這些報錯嚇到;它們只是在你尚未徹底輸入完畢時短暫的出現一下。
我希望你清楚為什么要把tragetValue做成一個實例變量。
你需要僅在viewDidLoad()這一個地方生成隨機數,然后存儲下來,直到用戶點擊Hit Me按鈕后,在showAlert()中讀取它。
將showAlert()改變成下面這個樣子(代碼框展現不全可以左右滑動):
@IBAction func showAlert() {
let message = "The value of the slider is: \(currentValue)" + "\nThe traget value is: \(tragetValue)"
let alert = ...
小貼士:你在文中任何地方的代碼里看到 ... 這種省略號的時候,我是要告訴你從這里開始不要做任何更改。(千萬注意不要真的把原來的代碼用省略號替換掉了!)
你輕易的添加了一個隨機數,并且將它存儲在targetValue里,并且在彈出窗口的消息中展現它。\(tragetValue)對你來說應該比較熟悉了,實際的隨機數會替換掉它。
\n這個符號是新出現的。它代表換行,就和word里敲一下回車鍵效果是一樣的,把文本弄成兩行這樣看起來會易讀一些。
運行app試試效果吧!
??:早先你用 + 操作符對兩個數字進行運算(就和數學里的一樣),但是這里的 + 用于將兩個字符串合并為一個字符串。
Swift允許同一個操作符進行不同的任務,具體依賴于參加運算的值的類型。如果 + 號兩邊是兩個數值,那么 + 號就是求和運算。但是如果是兩個字符串,那么 + 的作用就是把它們鏈接為一個字符串。
為這個游戲添加上回合機制
如果你點擊幾次Hit Me按鈕,你會發現這個隨機數從來沒變過。我恐怕這樣會嚴重影響游戲性。
這是因為你在viewDidLoad()中生成了這個隨機數后就再也沒管過它。viewDidLoad()僅僅是app啟動時創建視圖的時候被調用一次。
讓我們回頭看看工作清單,這里明確的寫著“在每一回合開始的時候生成一個隨機數”。讓我們來講講對于這個游戲,回合是什么概念。
當游戲剛開始時,玩家的分數為0,并且回合數為1。你把滑條置于中間位置(值為50處)并且生成一個隨機數。之后等待玩家點擊Hit Me按鈕,當玩家這樣做了以后,這一回合就結束了。
之后你需要計算玩家的分數,并且把這個分數加到總分里。然后將回合數加1,并且開始新的一個回合。在新的回合里,你需要將滑條的位置復位到中間位置并且生成一個新的隨機數,周而復始。
無論何時,當你思考“此時我們應該對這個app添加些什么功能”這類問題時,都應該新建一個方法。這個方法作為一個獨立的單元去實現你想要的功能(不要在一個方法里去做兩個功能)。
順著這一思路,在ViewController.swift里添加下面這個新的方法。
func startNewRound() {
tragetValue = 1 + Int(arc4random_uniform(100))
currentValue = 50
slider.value = Float(currentValue)
}
這段代碼放在文件中的任何位置都可以,但是必須在class ViewController的花括號內部,這樣編譯器就知道了它是屬于ViewController這個對象的。
這和你之前做的事情并沒有太大的不同,除了將設置新的一個回合的相關邏輯移到了屬于它自己的方法(startNewRound())里。這樣做的好處是你可以在其他任何地方隨時調用這套邏輯。
首先你可以在ViewDidLoad()調用這個新方法來為最初的一回合進行設置。回憶一下,ViewDidLoad()僅在app啟動時被調用一次,所以這里是進行第一回合設置的好地方。
把ViewDidLoad()改成下面這個樣子:
override func viewDidLoad() {
super.viewDidLoad()
startNewRound()
}
注意一下,你需要把之前存在語句刪除掉,替換為新的這個語句,僅僅調用一下startNewRound()方法。
當用戶點擊Hit Me按鈕后,你也需要調用這個方法,為下一局的開始做好設置,可以通過在showAlert()方法中調用實現這一目的。
把showAlert()改成下面這個樣子:
@IBAction func showAlert() {
. . .
startNewRound()
}
目前,view controller中的方法會在某些不同條件下分別被調用起來:viewDidLoad()會在app啟動時被執行,showAlert()會在玩家點擊Hit Me按鈕時被執行,sliderMoved()會在你拖動滑條時被執行,等等。這就是我們之前討論的所謂的事件驅動模型。
同時你也可以手動調用方法,就是你剛才做的事情。你讓對象中的一個方法向同一對象中的另一個方法傳遞消息。
在這個例子里,為了給新的一回合做配置,view controller自己發送消息給startNewRound()。iPhone會走到這個方法前并且逐條執行其中的語句。當startNewRound()這個方法中的語句全部執行完后,會回到調用它的方法(第一回合是viewDidLoad(),其他回合是showAlert()),繼續逐條執行其中剩余的語句。
有時你會看到這種調用方法的語句:
self.startNewRound()
如果把前面的self去掉,其實效果是一樣。回憶一下之前我說過的view controller是如何向自己發送消息的。沒錯,這就是self的意義所在(方法給自己所屬的對象發送消息)。
在一個對象上調用一個方法,常規寫法是這樣的:
receiver.methodName(parameters)
receiver就是接受消息的對象。如果你自己給自己發送消息,那么receiver就是self。但是因為向自己發送消息是非常頻繁的一個動作,不管在任何app中,所以可以省略這個關鍵字。
實話講,這并不是你第一次調用方法。addAction()是一個屬于UIAlertController的方法,present()是所有view controller共有的方法,包括你的。
當你用Swift編程,大部分工作就是在對對象上調用方法,因為這是你app中對象之間的通信方法。
我希望你能明白為什么要把這些邏輯塞到屬于它自己的一個方法里去。如果你不這樣做,那么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)
你可能會有自己的思路:“這段代碼生成了一個隨機數并且重置了滑條的位置,所以它大概應該是新的一回合開始時對數據的設置吧?”
也許你會為這段代碼添加注釋,以便以后查看,但是有什么能比新建一個方法更清晰明了的呢?
startNewRound()
這一行非常清楚的拼寫出了它想干什么。并且假如你想知道開始新的一回合時到底做了什么,你就可以去看看這個方法里具體的內容。
書寫良好的代碼會自己說話。我希望我已經讓你明白了對不同功能獨立建一個新的方法的價值。
運行app,確認你每次點擊Hit Me按鈕時,都生成了一個新的1到100之間的隨機數。
你同時也應該注意到,每一回合結束后滑條也會回到中間的位置。這是因為我們在startNewRound()中設置了currentValue等于50并且把告訴滑條回到這個位置。這和我們之前做的相反(之前你是讀取滑條的值,并且把這個值存儲到currentValue中),因為在每一回合開始時,讓滑條回到同樣的位置用戶體驗會好很多。
練習:僅僅是為了好玩,修改下代碼,讓滑條在每一回合開始不要恢復位置。
順便說一下,你也許想知道Float(...)和Int(...)這種東西是干嗎的:
targetValue = 1 + Int(arc4random_uniform(100))
slider.value = Float(currentValue)
Swift是一種被稱為‘強類型(strongly typed)’的語言,這就是說它對能放進容器里的積木形狀非常挑剔。例如:如果一個變量是Int(整數)那么你就不能把一個Float(單精度浮點數)的值放進去,反之亦然。
UISlider的值是Float型的,這是一種可以帶小數點的數,你之前應該在打印slider的值時見過,但是currentValue是Int(整數)型的,所以下面的語句不會執行:
slider.value = currentValue
編譯器會在這里報錯。有些編程語言會自動將Int轉換為Float,但是Swift要求你明確的確認這種轉換。
當你說“Float(currentValue)”時,編譯器拿出currentValue中存貯的整數并且將它轉換為一個新的Float型的值,這樣才能把這個值傳遞給UISlider。
類似的事情在用arc4random_uniform()時發生過,生產的隨機數先被轉換為Int(整數),然后才放到變量targetValue里。
因為Swift在值類型上比任何其他語言都嚴謹,所以很多初學者在這里會有些轉不過彎來。不幸的是,Swift的報錯信息并不能總是準確的反映這一情況,所以嚴格的判斷每個變量的值類型,就主要靠你自己了。
你可以記住,每當你看到“cannot assign value of type ‘something to type ’ to something else”這種報錯信息時,那么就是你試圖將不同類型的數據混在一起。解決的辦法就是,精確的制定某些值轉換為其他類型的,就像我們剛才做的那樣。
把targetValue的值放到標簽里去
你已經成功的生成了一個隨機數,并且將它存儲到一個實例變量里去了,這樣,之后你就可以讀取這個數了,非常好。
現在你將要把這個隨機數(也就是游戲中的目標值)顯示在屏幕上(游戲界面上,不是提醒窗口中)。如果不這樣做,那么玩家就不知道到底目標是多少,游戲也就無法進行下去了。
當你在storyboard中布置界面時,你已經添加了一個標簽(Label)用于展示目標值(targetValue),就是右上角的那個。我們要做的就是把targetValue這個變量中的值放到這個標簽上去。為了到達這一目的,你需要完成以下兩件事:
1、創建屬于這個標簽(label)的輸出(outlet),這樣你才可以給它傳遞消息。
2、把targetValue的值傳遞給標簽(label)的文本,這樣標簽就可以展示這個值了。
這和我們之前對滑條(slider)做的事情非常相似。回憶一下,你通過添加了一個@IBOutlet變量,用于在view controller中的任何地引用滑條(slider)。使用@IBOutlet變量你可以請求訪問滑條的值,通過slider.value語句。你接下來要對標簽做的事情,是一樣的。
在ViewController.swift中,添加下面的語句,就添加在滑條的@IBOutlet變量下面就好:
@IBOutlet weak var targetLabel: UILabel!
打開Main.storyboard,單擊選中右上角的那個標簽(就是預先設置為100的那個)。
打開鏈接檢查器,并且將New Referencing Outlet拖拽到View Controller上(下圖中黃色標簽的那個)
在彈出的小窗口中選擇targetLabel,之后鏈接就好了。
之后,在startNewRound()方法的下面添加一個新的方法:
func updateLabels() {
targetLabel.text = String(targetValue)
}
我們在這里需要新建一個方法是因為你也許會在不同的地方調用它。
方法的名字清楚的表明了它的作用:這個方法是用戶更新標簽的文本。目前僅僅是更新一個標簽的文本,但是之后我們會把其他的標簽更新也放到這個方法中來,比如總分(total score),回合數(round number)。
updateLabels()方法中的語句,對你來說應該一點都不陌生,也許你會有一點點疑問,為什么不能簡單的寫成下面這個樣子呢?
targetLabel.text = targetValue
答案是:你不能把一個數據類型放到與之不同的數據類型的變量中去。方形的積木并不適合圓形的孔。
targetLabel的outlet引用了一個UILabel的對象。而UILabel的屬性是文本,這種一種String(字符串型)的對象。你僅可以將String型的變量放進文本,但是上面那個例子中,你放進文本的目標targetValue是Int(整數)型的。這樣做不會有好結果,因為Int和String是兩個不同類型的數據。
所以你必須將Int轉換為String,這就是String(targetVlaue)的作用。它和你之前見過的Float()和Int()是一樣的。
僅僅是滿足你的好奇,你也可以用之前我們用的字符串插值的方法把targetValue傳遞給targetLabel,像這樣:
targetLabel.text = "\(targetValue)"
你更喜歡用那種方法就因人而異了。這兩種方法的效果是一樣的。
注意一下,updateLabels()是一個標準方法,它不像動作方法(Action Method)那樣依附于某個用戶控件(UI controls),所以你調用它之前,就這樣把它放著就行。(updateLabels() 的前面沒有@IBAction,所以它是一個標準方法)。
從游戲的邏輯上講,我們應該在每一回合開始的時候調用updateLabels(),也就是說updateLabels()應該緊接著startNewRound()方法執行,因為我們必定是在新的一回合開始時,才計算一個新的隨機數作為新的目標。
目前,我們在viewDidLoad()和showAlert()這兩個地方調用了startNewRound()方法,所以我們也同時需要在這兩個地方調用updateLabels()方法:
將viewDidLoad()和showAlert()方法修改為下面這個樣子:
override func viewDidLoad() {
super.viewDidLoad()
startNewRound()
updateLabels()
}
@IBAction func showAlert() {
. . .
startNewRound()
updateLabels()
}
你可以僅僅敲updateLabels()的前幾個字母,比如upd,然后Xcode會自動檢測出這個方法,之后你只需要敲一下回車就可以,對于其他的任何方法,變量也都是如此。
運行app并且確認隨機數已經作為目標顯示在屏幕上了。這應該使游戲的目標變得清晰些了。
你可以在03-Outlet中找到相關代碼。(請支持正版_)
動作方法(action method)和標準方法(normal method)
動作方法和標準方法有什么區別呢?
答案是:沒有區別。
動作方法和其他任何方法都是一樣的。唯一特殊的就是它們有一個特殊的說明符@IBAction。這一標識符允許界面建造器(Interface Bulider)能看到這個方法,這樣你才可以把它們和你的buttons(按鈕),slider(滑條)、等控件鏈接起來。
其他方法,比如viewDidLoad(),就沒有@IBAtion說明符。這是一個好事,因為所有的故意傷害罪都是發生在企圖把這類方法和buttons等控件鏈接起來,沒有@IBAtion說明符就不能鏈接,沒有鏈接就沒有傷害。
下面這些是動作方法(action method)的一般形式:
@IBAction fund showAlert()
你也可以通過一個參數請求相關的對象的動作方法
@IBAction func sliderMoved(_ slider: UISlider)
@IBAction func buttonTapped(_ button: UIButton)
第一個在滑條被拖動時觸發,第二個在按鈕被點擊時觸發。
但是下面的方法不能被界面建造器(Interface Bulider)當作動作方法處理:
func updateLabels()
它沒有@IBAction的標記,這樣界面建造器(Interface Bulider)就看不到它。如果要使用func updateLabels(),你就只能自己調用了。
如果你一直堅持讀到了這里,那么我猜,你也許已經喜歡上編程了。
這僅僅是我們4本自學教程中的第一課的一部分。整個巨大的教程還有三本書要學,并且在每節課你都會從設計草圖到最終代碼完整的做完一個app。
課程的設計是從簡單到中級水平安排的。每一個app都要比前面一個更難一些。它們加起來幾乎涵蓋了全部關于iOS開發的內容,你可以使用這些知識來做屬于自己的app。
在本系列的課程結束時,你會學到Swift和iOS開發工具的全部精要內容。更重要的是,你會掌握如何將各種不同的東西組合起來以到達想要的目的,以及像一個專業開發者那樣去分析解決問題。
我有充分的信心,當你堅持學完本系列的課程后,你一定有能力將自己的想法轉換為實際的app。
到目前為止,也許很多事情你都搞不清楚,但是你已經可以像一個程序員那樣獨立思考了-并且你要做好進入這個令人激動的iPhone和iPad開發者的世界。
以下是一些我們將要教會你的精華內容:
如何用Swift編程:即使你之前沒有任何編程方面的經驗,或者說編程對你來說是令人恐懼的。
如何像一個開發者那樣思考:你將超過那些僅僅會把代碼塞進編輯器的程序猿(原文是code monkey,很形象)。作為一個開發者,你將通過思考,對那些困難的計算問題給出創造性的解決方法。一旦你掌握了這個技術,就沒有你不能實現的想法了。
體驗SDK:iOS的SDK非常龐大,我們沒有任何可能做到面面俱到,幸好我們也不需要這樣做。你只需要掌握基本的功能模塊,比如navigation controller(導航控制器),table views(表視圖)。你同時也會學習如何使用網絡服務以及如何開發iPad的app。一旦你理解了這些基本原理,你可以輕易的自己搞定其他所有SDK的原理。
如何把app打扮的更好看:美化app比編程還要重要一些,畢竟這是一個看臉的世界。我們會通過圖形和動畫技術來更好的設計用戶界面。在本節課中,你會對這個游戲app來個大整容,并且使它支持所有類型的iPhone。
最后也是最棒的:我們所有的知識點都基于Swift和iOS的最新版本,比如Auto Layout(自動布局)和Universal Storyboard(通用故事模版)。不會像很多市面上的其他書那樣,還在將過時的東西(這一點很重要,凡事學過Swift的同學都應該體會過,舊的版本不是簡單的版本過低而已,是根本無法被編譯運行了都)。每次新的iOS版本發布,都會對開發工具進行相應的改進,這些將成為你的優勢。
我們也不會進行枯燥的理論課程,而是手把手的練習和糾正!當你在實際做app的過程當中,我會解釋你做的一切是如何工作的,并且用大量的配圖來清晰的展示應該怎么做。