Swift3.0學(xué)習(xí)筆記(一)

開篇

接觸Swift大概有1個多月的時間了,剛開始學(xué)習(xí)Swift的那段日子真是苦不堪言,面對著一個陌生的語言,真是不知道該從哪里著手開始學(xué)習(xí),所以跌跌撞撞地到處碰壁,踩坑。不過經(jīng)過了這一段時間自己的摸索,以及向各路大神請教,加上網(wǎng)上各種檢索資料,到現(xiàn)在應(yīng)該算是一腳踏入了Swift的大門了,盡管另外一只腳還在門外,但我會不斷地學(xué)習(xí)的。
因為我是從Objective-C語言轉(zhuǎn)過來學(xué)習(xí)Swift的,所以剛開始接觸Swift的時候,總想著在Swift里怎么實現(xiàn)OC的那些風(fēng)格習(xí)慣,比如說使用OC中的宏定義、PrefixHeader文件等等,我想,會OC的童鞋們在學(xué)習(xí)Swift時可能也會有和我一樣的想法,因此,在這里我將我學(xué)習(xí)Swift 的一些經(jīng)驗分享給大家,可能有些內(nèi)容我說的不準(zhǔn)確,甚至是錯誤的,還請大家?guī)臀抑赋?,另外,我有個和大家一起討論Swift3.0學(xué)習(xí)的技術(shù)交流群185826825,歡迎大家來與我們共同學(xué)習(xí)!我的本系列其它文章:
Swift3.0學(xué)習(xí)筆記(二)

寫在前面

當(dāng)嘗試著用一個自己陌生的語言,去實現(xiàn)一個自己想要達到的功能,是很令人興奮的。所以,在文章的開始,我想先用一個極其簡單的demo作為Swift學(xué)習(xí)的開始,這個demo的功能是頁面上有一個按鈕,點擊按鈕跳轉(zhuǎn)到另一個頁面。

大家看這段代碼,是不是發(fā)現(xiàn)和OC的風(fēng)格很像呢?是不是發(fā)現(xiàn)自己很容易就能看懂呢?其實我想說的是,世上無難事,只怕有心人,只要你愿意花時間去學(xué)習(xí),你就會發(fā)現(xiàn)其實他并不難。

基礎(chǔ)

  • 導(dǎo)入文件###

在Swift中,同一個工程項目不需要引入各自的類文件,比如我新建了一個工程,里面有兩個ViewController,我在vc_A中希望引用vc_B的某個公開屬性,這時在我的vc_A中是不需要引入vc_B的文件的。
不在本工程內(nèi)創(chuàng)建的文件,如一些系統(tǒng)庫,或是通過CocoaPods加入到工程的,在使用時則需要引入到工程內(nèi),引入時也區(qū)別OC,簡單使用import 庫名即可,例如:

import UIKit
import ReactiveSwift
  • 常量與變量###

在Swift中,使用let來表示常量,var來表示變量,所謂常量,即為不可改變的量,比如你聲明一個UIButton對象,后面不會給這個對象賦值成別的什么按鈕對象,初始化時即在內(nèi)存中給這個對象開辟了一塊空間,后面不會去改變這個對象的地址,因此,你可以這樣來創(chuàng)建這個對象:

let btn = UIButton(type: .system)

改變對btn的一些屬性設(shè)置,不會影響這個對象在內(nèi)存中的地址變化,因此,也就不需要將btn設(shè)置成var類型,這個看你的需求而定。
像在OC中常使用的NSMutableArray,在Swift中沒有類似可變數(shù)組這樣的類,可以直接聲明一個數(shù)組類型的變量來達到同樣的效果,比如這樣:

var array: Array<String>

需要說明的是,Array<String>為字符串類型的數(shù)組,關(guān)于數(shù)組后面會介紹。

  • 數(shù)據(jù)類型###

大體上數(shù)據(jù)類型和OC也沒有什么差別,布爾類型的值從OC的YES/NO換成了true/false,其它值得注意的就是Swift本身是類型安全的語言,因此像在OC中習(xí)慣使用的小數(shù),比如CGFloat和Float在使用運算符進行運算時就會報類型不一致的錯誤了:

修改方法是需要將其中的一個進行類型轉(zhuǎn)換,以保證兩個進行運算的值的類型是一致的:

let a: CGFloat = 0.3
let b: Float = 0.4
let sum = Float(a) + b

值得說明的有兩點,

  1. Swift的變量和常量在聲明時可以不說明它的類型,編譯器會通過初始化的值對該變量或常量進行類型推斷。

通過這張圖我們可以看出來,我在聲明常量a時,并沒有指定a的數(shù)據(jù)類型,而是通過給a進行初始化賦了一個值0.3,這時候編譯器會根據(jù)初始化的值對常量a進行類型推斷,推斷出的結(jié)果是常量a是一個Double類型的常量。

  1. Swift中不需要;作為句尾結(jié)束符,因此在Swift中對于空格的使用就要注意一些,比如在賦值符=的左右兩邊,都必須有至少一個空格才能正常編譯通過。
  • 輸出函數(shù)###

由于Swift可以兼容OC,因此我們?nèi)钥梢岳^續(xù)使用NSLog輸出函數(shù)來進行輸出,同樣,Swift也提供了自己的輸出函數(shù),Print,這個函數(shù)中不再需要占位符了,你希望輸出一個變量類似這樣:

let name = "Shaw"
print("Hello \(name)")

或者這樣

let name = "Shaw"
print("Hello" + name)
  • 可選類型###

這個可以算是Swift相較OC變化較大的內(nèi)容了,這就是你在閱讀Swift的代碼時經(jīng)常能夠看到的在一個變量的后面,跟了一個?或者!,這就跟可選類型相關(guān)。
聲明一個可選類型的變量,表示這個變量可以被賦值為nil,這個不同于OC,在OC里,所有的對象都可以被賦值為nil,在編譯時不會報錯,但是Swift不可以,如果一個對象在聲明時沒有聲明成可選類型,那么這個對象在編譯時是不允許被賦值為nil的。比如下面這樣:


這樣就是不允許的,這時,我們發(fā)現(xiàn)報的這個錯誤編譯器可以幫我們自動修正,修正后就是這個樣子了:

var x: UIImageView? = nil

可以發(fā)現(xiàn),編譯器只是幫我們在數(shù)據(jù)類型的后面增加了一個?,這樣就可以將變量x賦值為nil了。接下來我們給這個UIImageView對象賦一張圖片,像這樣:

x = UIImageView.init(image: UIImage.init(named: "abc"))

接下來,我們再聲明一個UIImage類型的常量y,并將變量x的image屬性的值賦給y,這時候我們不允許y為nil,我們這樣做:


你突然發(fā)現(xiàn)編譯器給我們報了兩個錯誤,先不要著急,讓我們來一一看這兩個錯誤都是什么,

  1. 第一個錯誤點在x的下面,說可選類型的UIImageView沒有打開,你是要使用'!'或者'?'么?,這個錯誤發(fā)生的原因和之前我們在說Float和CGFloat那部分的問題是一樣的,由于Swift是類型安全的語言,因此一旦你聲明確定了一個變量或常量的類型,那么這個變量或常量無論在編譯時還是運行時都只能是這個類型的,對于剛才變量x下面的那個錯誤點,因為只有真正的UIImageView對象,才會有image屬性,而由于我們在聲明變量x的類型時,將x聲明成了可選類型,也就是允許x = nil,如果在訪問x的image屬性前,x的值是nil的話,程序運行就會崩潰,所以編譯器為了避免這個直接導(dǎo)致崩潰的問題發(fā)生,在編譯時會要求我們將可選類型的變量進行解包操作,只有解包后的變量x的數(shù)據(jù)類型才是真正的UIImageView類型,解包的方式就是在可選類型變量的后面加上?或者!即可,那么這二者的區(qū)別又是什么呢?
    ?表示嘗試將這個變量或常量進行解包,如果解包后x的值是nil,那么程序?qū)⒉辉偃ピL問x的image屬性;!則不同,其表示強制對x進行解包,如果發(fā)現(xiàn)解包后的x的值是nil,則程序會崩潰,因此需要慎用!。
  2. 明白了第一個錯誤是如何產(chǎn)生的,第二個問題也就迎刃而解了,同樣,我們在給一個UIImage類型的常量y賦值時,編譯器不允許y被賦值為nil,因此會強制要求你將x.image后面加上!的,注意,這時候后面不可用?,原因還是由于Swift是類型安全的語言,不能嘗試對x.image進行解包,如果你解出來是個nil怎么辦?因此編譯器直接讓你強制解包,解出來是nil的話就搞崩潰你。
    下面有兩種對于剛才這個問題的正確寫法,
let y: UIImage = x!.image!
let y: UIImage = (x?.image)!

對于這兩種寫法,都是正確的,只不過解包的思路有些不同,上面那種是先將x強制解包成UIImageView對象,再對他的image屬性進行強制解包;下面那種是先嘗試將x解包,然后訪問他的image屬性,最后對訪問的這個屬性進行強制解包。
說到這也許你會問,雖然大概明白了什么是可選類型,以及什么是解包,為什么要解包,但是你在開發(fā)時,仍然不可避免的忽略掉這些,不要捉急,機智的編譯器已將替大家考慮到這個問題了,他會在你寫代碼的時候,悄悄的自動為你加上這些符號,如果你真的寫錯了的話,他還能幫你自動修正,是不是發(fā)現(xiàn)這時候的Xcode真的挺可愛的呢?

  • 運算符###

基本的運算符還都和OC一致,不過在使用運算符進行運算的時候需要注意類型一致,另外,在Swift3之前的版本中,支持對浮點數(shù)進行求余操作,但是Swift3不再支持了,系統(tǒng)提示使用一個方法進行代替:

var  a: Float = 10.5
//a = a % 3
a = a.truncatingRemainder(dividingBy: 3)

輸出結(jié)果1.5
以下表格列出了在Swift3中支持的基本運算符,舉例: x = 10, y = 20

運算符 運算 結(jié)果
+ x + y 30
- x - y -10
* x * y 200
/ x / y 0
% x % y 10

對于OC和Swift3之前的版本所支持的++--運算,在Swift3中只支持這樣的形式:

實例 等價 結(jié)果
x += 10 x = x + 10 20
y -= 1 y = y - 1 19

Swift3中的邏輯運算符和位運算符都與OC沒有什么差異,需要注意的是,像這樣在OC中可以用位運算符中的邏輯或囊括的多個枚舉值:

[UIView animateWithDuration:0.1 delay:0 options:
UIViewAnimationOptionAutoreverse
| UIViewAnimationOptionAllowUserInteraction  
animations:^ {
       
} completion: nil];

在Swift中寫起來要麻煩一些:

UIView.animate(withDuration: 0.1, delay: 0, options: 
(UIViewAnimationOptions(rawValue: 
UIViewAnimationOptions.autoreverse.rawValue 
| UIViewAnimationOptions.allowUserInteraction.rawValue)), 
animations: {
            
}, completion: nil)

另外,在Swift3中,增加了一個符號??,該符號的用法如下:

實例 等價
let a = b ?? c let a = b != nil ? b! : c

舉例說明,一個函數(shù)的功能是接收一個可選字符串類型的參數(shù),返回一個字符串,如果傳進來的是nil,就將參數(shù)重新賦值成一個既定的字符串并返回,代碼如下:

func showMessage(msg: String? = nil) -> String {
      let msg = msg ?? "默認(rèn)字符串"
      return msg
}

Swift3.0的區(qū)間運算符:

實例 等價 說明
0...10 0 <= x <= 10 從0到10的閉區(qū)間
0..<10 0 <= x < 10 從0到10的左閉右開區(qū)間
  • 數(shù)據(jù)存儲###

  1. 枚舉####

你可以聲明一個枚舉,像這樣:

enum ControlCMD {
          case up, right, down, left
}

比如我們現(xiàn)在有個需求,滑動手指時輸出一個手指滑動的方向的英文,在Swift里我們只需要這樣實現(xiàn):

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let leftGR = UISwipeGestureRecognizer
            .init(target: self, action: #selector(swipe(_:)))
        leftGR.direction = .left
        let rightGR = UISwipeGestureRecognizer
            .init(target: self, action: #selector(swipe(_:)))
        rightGR.direction = .right
        let upGR = UISwipeGestureRecognizer
            .init(target: self, action: #selector(swipe(_:)))
        upGR.direction = .up
        let downGR = UISwipeGestureRecognizer
            .init(target: self, action: #selector(swipe(_:)))
        downGR.direction = .down
        self.view.addGestureRecognizer(leftGR)
        self.view.addGestureRecognizer(rightGR)
        self.view.addGestureRecognizer(upGR)
        self.view.addGestureRecognizer(downGR)
    }
    
    enum ControlCMD: String {
        case up, right, down, left
    }
    
    func swipe(_ sender: UISwipeGestureRecognizer) {

        switch sender.direction {
        case UISwipeGestureRecognizerDirection.up:
            self.sendMessage(cmd: .up)
        case UISwipeGestureRecognizerDirection.down:
            self.sendMessage(cmd: .down)
        case UISwipeGestureRecognizerDirection.left:
            self.sendMessage(cmd: .left)
        case UISwipeGestureRecognizerDirection.right:
            self.sendMessage(cmd: .right)
        default: break
        }

    }
    
    func sendMessage(cmd: ControlCMD) {
        print("滑動的方向" + cmd.rawValue)
    }
}

注意,我在聲明枚舉時,將枚舉類型指定為String類型的枚舉,這樣,我在發(fā)送消息時就可以使用cmd.rawValue來訪問枚舉值的字符串了。
Swift中的枚舉還有一些更高級的用法,因為我暫時還沒有用過,所以也不在此描述了,以后遇上時再補充上。

  1. 元組####

對于元組這個概念,這是OC中所沒有的,我理解的元組是將多個值組合成為一個值,感覺有點像數(shù)組,但是元組中的值的類型可以是任意類型的,舉個例子:

let tuple = ("abc", 1, 0.5, [UIImage()])

這就是一個元組,元組中可以有多個元素,也可以只有一個元素,當(dāng)然,由于元組就是為了存儲多個值的,如果只有一個值也就不需要元組,多個值的時候,我們可以像數(shù)組那樣,通過使用序號來訪問元組中的元素,比如這樣:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容