1. 程式人生 > >Swift 4.0 學習之基礎摘要一

Swift 4.0 學習之基礎摘要一

前提小知識:在Swift中,如果想要使用某一個類(cocoapods匯入的三方庫除外),是不用導標頭檔案的,因為Swift新增了一個OC中沒有的概念,叫“名稱空間”。只要在同一個名稱空間中的資源都是共享的,而且預設情況下,專案名稱就是名稱空間。

一:資料型別轉換

在Swift中,沒有隱式資料轉換,所有的轉換必須顯示,舉例如下:

//在OC中,所有資料都存在隱式轉換
int a = 1;
int b = 1.1;//在OC中這麼寫,系統會自動轉換成 b = 1;
float c = 1.1;
float sum = a + b + c;//在相加的等式中,雖然ab和c的資料型別不一樣,但是系統也會自動轉換成一樣的去計算,這就是隱式轉換
//但是在Swift中,沒有隱式轉換
let a: Int = 1 
let b: Int = 1.1 //直接會報錯
let c: Double = 1.1
let sum = a + b + c //這麼寫也會報錯,因為型別不一樣,必須顯示的轉換如下
let sum1 = a + b + Int(c) //所有資料必須轉換成同一個型別才能進行計算

二:分支語句

在C和OC中,有一個非0即真的概念,但是Swift沒有,舉例如下:

int num = 10;
if (num) {
//在OC中,是會走到這裡的,而且如果判斷為真只執行一個語句的話,外面的大括號是可以去掉的
}
let num = 10
if num { //但是在Swift裡,首先if後面跟的條件可以不加小括號,但是後面的大括號絕對不能省略; //第二點是,在Swift中,條件只能放bool值,取值只有truefalse,如這裡只放一個num就會報錯 }

在Swift中,switch語句與OC的區別

1、在Swift中,break可以省略,不會穿透執行下面的語句

2、在Swift中,一個case下面有多條語句或者宣告新的變數也不需要加大括號來確定作用域

3、在OC中,deafult位置可以隨便寫,並且可以省略。但是在Swift中,deafult只能寫在最後,並且絕大部分情況不能省略

三:迴圈語句

OC中常用的普通for迴圈 for(int i=0;i<10;i++){}在Swift3.0已經移除掉了,現在Swift用的for in 迴圈很具有Swift特色,舉例如下:

for var num in 0...10 {
//0...10表示包含頭尾的0到10之間所有的整數
//0..<10表示包含頭不包含尾的0到9之間所有的整數
//0...10這種條件區間內不能出現任何的空格
} 
//如果不關心迴圈本身的索引,可以直接用下劃線如下
for _ in 0...10 {
}

四:可選繫結

在Swift中,返回值或者資料型別後面加 ?表示可選型別,值可以為空,但是後面加 !的話,表示告訴編譯器,這個是一定有值的,相當於強制解析,如果沒有值的話,就會崩。這是前提。實際應用舉例如下:

let url = URL.init(string: "http://www.baidu.com")
//正常寫慣了OC的話,為了保證程式的穩定性,強制解析前一定會加判斷,通常會這麼寫
if url != nil {
    let request = URLRequest(url: url!)
}
//但是在工程中會有很多很多的可選型別,如果每個都這麼寫的話,看起來肯定不太優雅,所以Swift推出了一個可選繫結的寫法
if let url = url {
    let request = URLRequest(url: url)
}

五:陣列和字典

陣列和字典的建立和OC基本一致,不用寫前面的@而已,但是遍歷字典的時候,Swift由於有元祖這個東西在,改進的方便了一點,,舉例如下:

let dictionay = ["一":1,"二":2]
//如果是OC的話,遍歷這個字典會這麼寫,當然swift這麼寫也可以
for key in dictionay.keys {
    print(key)
}
//但是Swift還有一種寫法如下
for (k,v) in dictionay {//直接用一整個鍵值對來遍歷字典,在迴圈裡面能直接使用key和value
    print(k)
    print(v)
}
//在遍歷陣列的時候,Swift還提供了一種特別方便的方式
for (index,value) in array.enumerated() {
//index是下標,value是值
//這樣使得遍歷陣列能寫的更加簡潔優雅
}
//建立可變字典的時候,如果向上面那樣建立,那麼value的型別只能是統一的,這樣在實際應用中會有問題,所以可以這麼建立:
var dic = [String: Any]()
//賦值,有這個key就直接賦值,沒有這個key就會自動建立這個key然後賦值
dic["name"] = "馬化騰"
//合併字典
for (key , value) in dictionay {
    dic[key] = value
}

六:字串

OC中的字串是一個物件,繼承於NSObject,但是Swift中的字串是一個結構體,因此Swift中的字串效能比OC中要高,實際應用舉例如下:

var str1 = "zyt"
var str2 = "ssg"
//單純拼接兩個字串直接加就可以
str1 += str2
//如果兩個字串型別不一致的時候,可以用\()來拼接,如下
let age = 25
let name = "zyt"
//目標 name = zyt ,age = 25
var str = "name = \(name) , age = \(age)"
//如果想要實現例如時間這種顯示傳入4顯示04     04:03:25
var time = String.init(format: "%02d:%02d:%02d", 4,3,25)

字串的處理必然要提起擷取字串,這在字串的處理中屬於比較常用的,但是Swift在處理擷取字串的時候沒有一個很方便的系統api可以呼叫,所以目前來說,處理擷取字串大體有兩種方式

首先第一種:通過轉換成OC中的NSString來執行,舉例如下:

var aaaa:NSString = "aljdflkasjflkas"//通過定義字串型別為NSString來呼叫sub方法,也可這麼寫:var aaaa = "asldfjalksjf" as NSString  效果一樣
let nnn = aaaa.substring(with: NSMakeRange(0, 4))

第二種方式:雖然通過上面那種方式沒什麼問題,但是總覺得就截一個字串每次要這麼轉來轉去,感覺總歸有點low,因為Swift沒有系統封裝好這樣擷取字串的api,那就自己封裝一個吧,程式碼如下:

//寫一個String的類擴充套件
extension String {
    subscript(range: CountableClosedRange<Int>) -> Substring {//閉區間
        let sIndex = range.lowerBound
        var eIndex = range.upperBound
        if sIndex > (count - 1) {
            return ""
        }else if eIndex > (count - 1) {
            eIndex = count - 1
        }
        let start = index(startIndex, offsetBy: sIndex)
        let end   = index(startIndex, offsetBy: eIndex)
        return self[start...end]
    }
    subscript(range: CountableRange<Int>) -> Substring {//開區間
        let sIndex = range.lowerBound
        var eIndex = range.upperBound
        if sIndex > (count - 1) {
            return ""
        }else if eIndex > (count - 1) {
            eIndex = count
        }
        let start = index(startIndex, offsetBy: sIndex)
        let end   = index(startIndex, offsetBy: eIndex)
        return self[start..<end]
    }
}
//然後就直接可以呼叫了,直接傳入下標從幾到幾就可以了
let aaa = "alksdjflkajsf"
aaa[0...3]
aaa[1..<33]
aaa[22...222]//上面的方法已經做處理了,各種情況都能保證不會crash

七:函式

Swift的函式寫法最基礎的模式如下:

//基礎表現形式
func 函式名(傳入引數,多個用逗號隔開)-> 返回值型別 {
//如果沒有返回值,可以填 Void,也可以 -> () ,也可以什麼都不寫,直接函式名(傳入引數)後直接跟大括號
}

//實際應用中傳入引數可以有以下三種寫法
func sum(a: Int,y b: Int,_ c: Int) {
    print(a + b + c)
}
// a就正常寫法,y寫b前面表示外參,外面用y,函式內用b,c前面加 _ 表示外面呼叫時不顯示引數名,如下:
sum(a: 1, y: 2, 3)

八:閉包

說到閉包,用法跟OC的block是一樣一樣的,基本格式是 { ()->() in }
通常是放到函式的實參裡,舉一個實際應用的例子:
目標:建立一個scrollorView,上面有10個按鈕,要求有一定的可複用性,可維護性,可擴充套件性。程式碼如下:
override func viewDidLoad() {
        super.viewDidLoad()
        let sc = creatScrollorView(creatNumber: { () -> Int in
            return 10
        }) { (index) -> UIView in
            let btn = UIButton()
            btn.setTitle("\(index)", for: .normal)
            btn.backgroundColor = UIColor.yellow
            btn.frame = CGRect.init(x: index * width, y: 0, width: width, height: 50)
            return btn
        }
        //在Swift中,能不用self儘量不用self,self一般只在閉包中使用
        view.addSubview(sc)
    }
    func creatScrollorView(creatNumber:() -> Int, viewIndex:(Int) -> UIView) -> UIScrollView {
        let sc = UIScrollView.init(frame: CGRect.init(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 100))
        let count = creatNumber()
        for i in 0..<count {
            let subView = viewIndex(i)
            sc.addSubview(subView)
            sc.contentSize = CGSize.init(width: subView.bounds.width * CGFloat
        }
        return sc
    }
上面說到閉包和OC的block用法一樣,那麼當類的物件持有閉包,閉包的程式碼塊裡持有類的物件的時候,必然也會出現迴圈引用導致物件無法被釋放的問題。
在OC中,我們用一個弱指標去持有一個物件,然後在block的程式碼塊裡用這個弱指標去解決這個問題,程式碼如下:
__weak __typeof(&*self)weakSelf = self;
Swift其實也一樣,寫的更簡單一點而已
weak var weakSelf = self

九: 懶載入

懶載入是一個在專案中特別常用的東西,在OC中,一般是通過重寫getter方法來實現,但是在Swift裡,多了一個叫 lazy 的修飾符,多麼形象生動的命名。具體應用舉例如下:
//在Swift中只需要通過 “lazy” + “=” + “閉包” 就可以實現懶載入
lazy var dataList:[Any] = {
//而且看這裡,如果閉包是用來做懶載入的話,那麼()-> () in return 全都可以省略
        ["zyt", 1, (4 , 5), ("name","zyt"), ["age":"25"]]
    }()

十: setter–getter–方法

Swift的setter和getter方法跟OC的這兩個方法大致一樣,但是用法跟OC還是有區別的,比如上面說的懶載入。還有OC中常用的重寫setter方法,在Swift裡是這麼用的:
var aaa: String? {
    didSet {
    //設定完之後呼叫這個方法,Swift中用這個方法來代替OC中的重寫setter方法
    }
}
//如果只重寫了getter方法,那麼這個屬性稱之為 計算型 屬性
//相當於OC中的只讀屬性
//特點:計算型屬性是不佔用記憶體空間的
var age: Int {
    get {
        return 25
    }
}