第三篇、Swift基礎學習

1.常量與變量

什麼是常量和變量

在Swift中規定:在定義一個標識符時必須明確說明該標識符是一個常量仍是變量
使用let來定義常量,定義以後不能夠修改
使用var來定義變量,定義以後能夠修改
變量的基本使用

import UIKit
let a : Int = 10
// 錯誤寫法,當一個標識符定義爲常量時是不能夠修改的
// a = 20
var b : Int = 20
// 由於b定義爲變量,所以是能夠修改的
b = 30
常量和變量的使用注意:

注意:
在真實使用過程當中,建議先定義常量,若是須要修改再修改成變量(更加安全)
是指向的對象不能夠再進行修改.可是能夠經過指針得到對象後,修改對象內部的屬性
import UIKit
/*
 常量使用注意:
    1> 優先使用常量
    2> 常量的本質
 */
// 1.注意一:在開發中let/var在選擇時優先使用常量,防止不小被修改掉(let)
// 若是一個標識符不須要修改,可是聲明稱了變量,那麼編譯器會報警告
// 2.常量的本質:
// 含義:指向的內存地址不能夠修改,可是能夠經過內存地址,找到對應的對象,以後修改對象內部的屬性
/*
 OC中建立對象:
    UIView *view = [[UIView alloc] init];
    view = [[UIView alloc] init];
 Swift中建立對象:
    var view : UIView = UIView()
 */
/*
 變量的作法
    var view : UIView = UIView()
    view = UIView()
 */
// 建立常量View
let view = UIView()
// view = UIView() 錯誤作法
view.alpha = 0.5
// Swift中建立結構體:結構體類型()
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
// Swift中調用方法,統一使用點語法
view.backgroundColor = UIColor.red
建立對象補充

建立UIView對象,而且在UIView中添加UIButton
import UIKit
// 1.建立UIView對象
// OC : [[UIView alloc] initWithFrame:CGRect]
let viewRect = CGRect(x: 0, y: 0, width: 100, height: 100)
let view : UIView = UIView(frame: viewRect)
// 2.設置UIView的屬性
view.backgroundColor = UIColor.orange
// 3.建立UIButton
let btn : UIButton = UIButton(type: .custom)
// 4.設置UIButton的屬性
btn.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
btn.backgroundColor = UIColor.purple
/*
 Swift中枚舉類型:
 1> 若是能夠根據上下文推導出類型能夠直接.具體的類型
 2> 若是根據上下文推導不出具體的類型,則須要:類型.具體的類型
 */
btn.setTitle("按鈕", for: .normal)
btn.setTitleColor(UIColor.white, for: .normal)
// 5.將btn添加到UIView中
view.addSubview(btn)

 

2.數據類型

Swift類型的介紹

Swift中的數據類型也有:整型/浮點型/對象類型/結構體類型等等
先了解整型和浮點型
整型
有符號
Int8 : 有符號8位整型
Int16 : 有符號16位整型
Int32 : 有符號32位整型
Int64 : 有符號64位整型
Int : 和平臺相關(默認,至關於OC的NSInteger)
無符號
UInt8 : 無符號8位整型
UInt16 : 無符號16位整型
UInt32 : 無符號32位整型
UInt64 : 無符號64位整型
UInt : 和平臺相關(經常使用,至關於OC的NSUInteger)(默認)
浮點型
Float : 32位浮點型
Double : 64浮點型(默認)
// 定義一個Int類型的變量m,而且賦值爲10
var m : Int = 10
// 定義一個Double類型的常量n,而且賦值爲3.14
let n : Double = 3.14
Swift中的類型推導

Swift是強類型的語言
Swift中任何一個標識符都有明確的類型
注意:
若是定義一個標識符時有直接進行賦值,那麼標識符後面的類型能夠省略.
由於Swift有類型推導,會自動根據後面的賦值來決定前面的標識符的數據類型
能夠經過option+鼠標左鍵來查看變量的數據類型

/*
 類型推導
    1> Swift中任何一個標識符都有本身明確的類型
    2> 若是定義一個標識符時有直接給該標識符進行賦值,那麼標識符後面的類型能夠省略
    3> 編譯器會自動根據後面賦值的類型,推導出前面標識符的類型
    4> 能夠根據option + 鼠標左鍵,查看標識符的類型
 */
// m是Int類型
let m = 20
// n是Double類型
let n = 2.44
// view是UIView類型
var view = UIView()
// color是UIColor類型
let color = UIColor.red
Swift中基本運算

Swift中在進行基本運算時必須保證類型一致,不然會出錯
相同類型之間才能夠進行運算
由於Swift中沒有隱式轉換
數據類型的轉化
Int類型轉成Double類型:Double(標識符)
Double類型轉成Int類型:Int(標識符)
import UIKit
let m = 20
let n = 30.5
// 錯誤寫法 :
// Swift中沒有隱式轉化,不會自動將一個Int類型轉成Double類型,所以不一樣類型之間不能進行運算
// let result = m + n
// 正確作法
// 1> 將Int類型轉成Double : Double(標識符)
// 2> 將Double類型轉成Int : Int(標識符)
let result1 = Double(m) + n
let result2 = m + Int(n)

 

3.邏輯分支

一. 分支的介紹

分支即if/switch/三目運算符等判斷語句
經過分支語句能夠控制程序的執行流程
二. if分支語句

和OC中if語句有必定的區別
判斷句能夠不加()
在Swift的判斷句中必須有明確的真假
再也不有非0即真
必須有明確的Bool值
Bool有兩個取值:false/true
// 演練一:
let a = 10
// 錯誤寫法:
//if a {
//    print("a")
//}
// 正確寫法
if a > 9 {
    print(a)
}
// 演練二:
let score = 87
if score < 60 {
    print("不及格")
} else if score <= 70 {
    print("及格")
} else if score <= 80 {
    print("良好")
} else if score <= 90 {
    print("優秀")
} else {
    print("完美")
}
二.guard的使用

guard是Swift2.0新增的語法
它與if語句很是相似,它設計的目的是提升程序的可讀性
guard語句必須帶有else語句,它的語法以下:
當條件表達式爲true時候跳過else語句中的內容,執行語句組內容
條件表達式爲false時候執行else語句中的內容,跳轉語句通常是return、break、continue和throw
guard 條件表達式 else {
    // 條換語句
    break
}
語句組
例子
var age = 18
func online(age : Int) -> Void {
    guard age >= 18 else {
        print("回家去")
        return
    }
    print("能夠上網")
}
online(age)
三.switch分支

switch的介紹

Switch做爲選擇結構中必不可少的語句也被加入到了Swift中
只要有過編程經驗的人對Switch語句都不會感到陌生
但蘋果對Switch進行了大大的加強,使其擁有其餘語言中沒有的特性
switch的簡單使用

基本用法和OC用法一致
不一樣之處:
switch後能夠不跟()
case後能夠不跟break(默認會有break)
例子:
let sex = 0
switch sex {
case 0 :
    print("")
case 1 :
    print("")
default :
    print("其餘")
}
簡單使用補充:
一個case判斷中,能夠判斷多個值
多個值以,隔開
let sex = 0
switch sex {
case 0, 1:
    print("正常人")
default:
    print("其餘")
}
簡單使用補充:
若是但願出現以前的case穿透,則可使用關鍵字fallthrough
let sex = 0
switch sex {
case 0:
    fallthrough
case 1:
    print("正常人")
default:
    print("其餘")
}
switch支持區間判斷

什麼是區間?
一般咱們指的是數字區間:0~10,100~200
swift中的區間常見有兩種
半開半閉區間:0..<10 表示:0~9,不包括10
閉區間:010 表示:0~10
let score = 88
switch score {
case 0..<60:
    print("不及格")
case 60..<80:
    print("幾個")
case 80..<90:
    print("良好")
case 90..<100:
    print("優秀")
default:
    print("滿分")
}

 

4.循環使用

循環的介紹

在開發中常常會須要循環
常見的循環有:for/while/do while.
這裏咱們只介紹for/while,由於for/while最多見
for循環的寫法

區間for循環
for i in 0..<10 {
    print(i)
}
for i in 0...10 {
    print(i)
}
特殊寫法
若是在for循環中不須要用到下標i
for _ in 0..<10 {
    print("hello")
}
while和do while循環

while循環
while的判斷句必須有正確的真假,沒有非0即真
while後面的()能夠省略
var a = 0
while a < 10 {
    a++
}
do while循環
使用repeat關鍵字來代替了do
let b = 0
repeat {
    print(b)
    b++
} while b < 20

 

2、Foundation 的使用編程

1.字符串使用

字符串的介紹

字符串在任何的開發中使用都是很是頻繁的
OC和Swift中字符串的區別
在OC中字符串類型時NSString,在Swift中字符串類型是String
OC中字符串@」」,Swift中字符串」」
使用 String 的緣由
String 是一個結構體,性能更高
NSString 是一個 OC 對象,性能略差
String 支持直接遍歷
Swift 提供了 String 和 NSString 之間的無縫轉換
字符的定義

定義不可變字符串
// 1> 定義不可變字符串 : 使用let修飾
let str : String = "hello swift"
// str = "hello Objective-C" 錯誤寫法
定義可變字符串
// 2> 定義可變字符串 : 使用var修飾
var strM : String = "hello world"
strM = "hello china"
字符串的使用

獲取字符串的長度

獲取字符集合,再獲取集合的count屬性
let count = str.characters.count
字符串拼接

兩個字符串的拼接
let str1 = "Hello"
let str2 = "World"
let str3 = str1 + str2
字符串和其餘數據類型的拼接
let name = "why"
let age = 18
let info = "my name is \(name), age is \(age)"
字符串的格式化
好比時間:03:04
let min = 3
let second = 4
let time = String(format: "%02d:%02d", arguments: [min, second])
字符串的截取

Swift中提供了特殊的截取方式
該方式很是麻煩
Index建立較爲麻煩
簡單的方式是將String轉成NSString來使用
在標識符後加:as NSString便可
let urlString = "www.520it.com"
// Swift中經過 as 關鍵字能夠將String類型轉成NSString的類型
let header1 = (urlString as NSString).substring(to: 3)
let footer1 = (urlString as NSString).substring(from: 10)
let range1 = NSRange(location: 4, length: 5)
let middle1 = (urlString as NSString).substring(with: range1)
swift截取方式
let urlString = "www.520it.com"
let headerIndex = urlString.index(urlString.startIndex, offsetBy: 3)
let header2 = urlString.substring(to: headerIndex)
let footerIndex = urlString.index(urlString.endIndex, offsetBy: -3)
let footer2 = urlString.substring(from: footerIndex)
let startIndex = urlString.index(urlString.startIndex, offsetBy: 4)
let endIndex = urlString.index(urlString.startIndex, offsetBy: 9)
let range2 = Range(startIndex..<endIndex)
let middle2 = urlString.substring(with: range2)

 

2.數組的使用

數組的介紹

數組(Array)是一串有序的由相同類型元素構成的集合
數組中的集合元素是有序的,能夠重複出現
Swift中的數組
swift數組類型是Array,是一個泛型集合
數組的初始化

數組分紅:可變數組和不可變數組

使用let修飾的數組是不可變數組
使用var修飾的數組是可變數組
定義不可變數組

let array : [Any] = ["why", 18, 1.88]
定義可變數組
var arrayM = [Any]()
對數組的基本操做

// 添加數據
array.append("yz")
// 刪除元素
array.removeFirst()
// 修改元素
array[0] = "why"
// 取值
array[1]
數組的遍歷

// 遍歷數組
for i in 0..<array.count {
    print(array<i>)
}
// forin方式
for item in array {
    print(item)
}
// 設置遍歷的區間
for item in array[0..<2] {
    print(item)
}
// 遍歷數組的同時獲取下標值
let names = ["why", "yz", "lnj", "lmj"]
for (index, name) in names.enumerate() {
    print(index)
    print(name)
}
數組的合併

// 數組合並
// 注意:只有相同類型的數組才能合併
var array = ["why", "lmj","lnj"]
var array1 = ["yz", "wsz"]
var array2 = array + array1;
// 不建議一個數組中存放多種類型的數據
var array3 = [2, 3, "why"]
var array4 = ["yz", 23]
array3 + array4

 

3.字典的使用

字典的介紹

字典容許按照某個鍵來訪問元素
字典是由兩部分集合構成的,一個是鍵(key)集合,一個是值(value)集合
鍵集合是不能有重複元素的,而值集合是能夠重複的,鍵和值是成對出現的
Swift中的字典
Swift字典類型是Dictionary,也是一個泛型集合
字典的初始化

Swift中的可變和不可變字典
使用let修飾的數組是不可變字典
使用var修飾的數組是可變字典
// 定義一個可變字典
var dict1 : [String : Any] = [String : Any]()
// 定義一個不可變字典
let dict2 : [String : Any] = ["name" : "why", "age" : 18]
字典的基本操做

// 添加數據
dict["height"] = 1.88
dict["weight"] = 70.0
dict
// 刪除字段
dict.removeValueForKey("height")
dict
// 修改字典
dict["name"] = "lmj"
dict.updateValue("lmj", forKey: "name")
dict
// 查詢字典
dict["name"]
字典的遍歷

// 遍歷字典中全部的值
for value in dict.values {
    print(value)
}
// 遍歷字典中全部的鍵
for key in dict.keys {
    print(key)
}
// 遍歷全部的鍵值對
for (key, value) in dict {
    print(key)
    print(value)
}
字典的合併

// 字典的合併
var dict1 = ["name" : "yz", "age" : 20]
var dict2 = ["height" : 1.87, "phoneNum" : "+86 110"]
// 字典不能夠相加合併
for (key, value) in dict1 {
    dict2[key] = value
}

 

4.元組的使用

元組的介紹

元組是Swift中特有的,OC中並無相關類型
它是什麼呢?
它是一種數據結構,在數學中應用普遍
相似於數組或者字典
能夠用於定義一組數據
組成元組類型的數據能夠稱爲「元素」
元組的定義

元組的常見寫法
// 使用元組描述一我的的信息
("1001", "張三", 30, 90)
// 給元素加上元素名稱,以後能夠經過元素名稱訪問元素
(id:"1001", name:"張三", english_score:30, chinese_score:90)
元組的簡單使用

用元組來描述一個HTTP的錯誤信息
// 元組:HTTP錯誤
// let array = [404, "Not Found"]
// 寫法一:
let error = (404, "Not Found")
print(error.0)
print(error.1)
// 寫法二:
let error = (errorCode : 404, errorInfo : "Not Found")
print(error.errorCode)
print(error.errorInfo)
// 寫法三:
let (errorCode, errorIno) = (404, "Not Found")
print(errorCode)
print(errorIno)

 

5.可選類型的使用json

可選類型的介紹

注意:
可選類型時swift中較理解的一個知識點
暫時先了解,多利用Xcode的提示來使用
隨着學習的深刻,慢慢理解其中的原理和好處
概念:
在OC開發中,若是一個變量暫停不使用,能夠賦值爲0(基本屬性類型)或者賦值爲空(對象類型)
在swift開發中,nil也是一個特殊的類型.由於和真實的類型不匹配是不能賦值的(swift是強類型語言)
可是開發中賦值nil,在所不免.所以推出了可選類型
可選類型的取值:
空值
有值
定義可選類型

定義一個可選類型有兩種寫法
最基本的寫法
語法糖(經常使用)
// 錯誤寫法
// let string : String = nil
// 正確寫法:
// 注意:name的類型是一個可選類型,可是該可選類型中能夠存放字符串.
// 寫法一:定義可選類型
let name : Optional<String> = nil
// 寫法二:定義可選類型,語法糖(經常使用)
let name : String? = nil
可選類型的使用

// 演練一:給可選類型賦值
// 定義可選類型
var string : Optional<String> = nil
// 給可選類型賦值
// 錯誤寫法:所以該可選類型中只能存放字符串
string = 123
// 正確寫法:
string = "Hello world"
// 打印結果
print(string)
// 結果:Optional("Hello world")\n
// 由於打印出來的是可選類型,全部會帶Optional
// 演練二:取出可選類型的值
// 取出可選類型的真實值(解包)
print(string!)
// 結果:Hello world\n
// 注意:若是可選類型爲nil,強制取出其中的值(解包),會出錯
string = nil
print(string!) // 報錯
// 正確寫法:
if string != nil {
    print(string!)
}
// 簡單寫法:爲了讓在if語句中能夠方便使用string
// 可選綁定
if let str = string {
    print(str)
}
真實應用場景

目的:讓代碼更加嚴謹
// 1.將字符串類型轉成Int類型
let str = "123"
let result : Int? = Int(str) // nil/Int
// 2.根據文件名稱,讀取路徑
let path : String? = Bundle.main.path(forResource: "123.plist", ofType: nil)
// 3.根據string,建立URL
let url = URL(string: "http://www.520it.com/小碼哥")
// 4.從字典中取內容
let dict : [String : Any] = ["name" : "why", "age" : 18]
dict["name"]
dict["height"]

 

6.類型轉化(as)

常見的類型轉化符號

as : 將實例轉成某一種類型
例子

// 1.定義數組
let array : [AnyObject] = [12, "why", 1.88]
// 2.取出第二個元素
let objc = array[1]
// 3.將objc轉成真正的類型來使用
// 3.1.as? 將AnyObject轉成可選類型,經過判斷可選類型是否有值,來決定是否轉化成功了
let age = objc as? Int
print(age) // 結果:Optional(12)
// 3.2.as! 將AnyObject轉成具體的類型,可是注意:若是不是該類型,那麼程序會崩潰
let age1 = objc as! Int
print(age1) // 結果:12

 

7.函數使用

函數的介紹

函數至關於OC中的方法
函數的格式以下
func 函數名(參數列表) -> 返回值類型 {
    代碼塊
    return 返回值
}
func是關鍵字,多個參數列表之間能夠用逗號(,)分隔,也能夠沒有參數
使用箭頭「->」指向返回值類型
若是函數沒有返回值,返回值爲Void.而且「-> 返回值類型」部分能夠省略
常見的函數類型

// 1.沒有參數,沒有返回值的函數
func about() -> Void {
    print("iPhone7")
}
about()
func about1() {
    print("iPhone7")
}
about1()
// 2.有參數, 沒有返回值的函數
func callPhone(phoneNum : String) {
    print("打電話給\(phoneNum)")
}
callPhone(phoneNum: "+86 110")
// 3.沒有參數, 有返回值的函數
func readMsg() -> String {
    return "吃飯了嗎?"
}
let msg = readMsg()
// 4.有參數有返回值的函數
func addTwoNum(num1 : Int, num2 : Int) -> Int {
    return num1 + num2
}
let result = addTwoNum(num1: 20, num2: 30)
函數的使用注意

注意一: 外部參數和內部參數
在函數內部能夠看到的參數,就是內部參數
在函數外面能夠看到的參數,就是外部參數
默認全部的參數都是外部參數和內部參數
若是不想要外部參數,能夠在參數名稱前加_
// 1.內部參數&外部參數
/*
func sum(num1 : Int, num2 : Int) -> Int {
    return num1 + num2
}
sum(num1: 20, num2: 30)
*/
/*
func sum(_ num1 : Int,_ num2 : Int) -> Int {
    return num1 + num2
}
sum(20, 30)
*/
func sum(abc num1 : Int, cba num2 : Int) -> Int {
    return num1 + num2
}
sum(abc: 20, cba: 30)
// sum(20, 30)
注意二: 可變參數
swift中函數的參數個數能夠變化,它能夠接受不肯定數量的輸入類型參數
它們必須具備相同的類型
咱們能夠經過在參數類型名後面加入(…)的方式來指示這是可變參數
// 2.可變參數
func sum(nums : Int...) -> Int {
    var total = 0
    for num in nums {
        total += num
    }
    return total
}
sum(nums: 20, 30, 40, 50)
func myPrint(_ items : Any...) {
    var strM : String = "\(items[0])"
    for i in 1..<items.count {
        strM = strM + " " + "\(items<i>)"
    }
    print(strM)
}
print(20, 30, 40)
myPrint(20, 30, 40)
注意三: 默認參數
某些狀況,若是沒有傳入具體的參數,可使用默認參數
func makeCoffee(coffeeName : String = "雀巢") {
    print("製做了一杯愛心\(coffeeName)咖啡")
}
makeCoffee(coffeeName: "拿鐵")
makeCoffee(coffeeName: "摩卡")
makeCoffee()
注意四: 引用類型(指針的傳遞)
默認狀況下,函數的參數是值傳遞.若是想改變外面的變量,則須要傳遞變量的地址
必須是變量,由於須要在內部改變其值
Swift提供的inout關鍵字就能夠實現
對比下列兩個函數
// 4.指針參數
var m = 20
var n = 30
func swapNum(num1 : inout Int, num2 : inout Int) {
    let temp = num1
    num1 = num2
    num2 = temp
}
swap(&m, &n)
print("m:\(m) n:\(n)")

 

8.枚舉類型

枚舉類型的介紹

概念介紹
枚舉定義了一個通用類型的一組相關的值,使你能夠在你的代碼中以一個安全的方式來使用這些值。
在 C/OC 語言中枚舉指定相關名稱爲一組整型值
Swift 中的枚舉更加靈活,沒必要給每個枚舉成員提供一個值.也能夠提供一個值是字符串,一個字符,或是一個整型值或浮點值
枚舉類型的語法
使用enum關鍵詞而且把它們的整個定義放在一對大括號內
enum SomeEnumeration {
// enumeration definition goes here
}
枚舉類型的定義

如下是指南針四個方向的一個例子
case關鍵詞代表新的一行成員值將被定義
不像 C 和 Objective-C 同樣,Swift 的枚舉成員在被建立時不會被賦予一個默認的整數值
在上面的CompassPoints例子中,North,South,East和West不是隱式的等於0,1,2和3
enum CompassPoint {
  case North
  case South
  case East
  case West
}
定義方式二:多個成員值能夠出如今同一行上
enum Planet {
  case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
給枚舉類型賦值

枚舉類型賦值能夠是字符串/字符/整型/浮點型
注意若是有給枚舉類型賦值,則必須在枚舉類型後面明確說明具體的類型
// 1.枚舉類型的賦值
enum CompassPoint : Int {
  case North = 1
  case South = 2
  case East = 3
  case West = 4
}
enum Planet {
  case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
// 2.枚舉類型的使用
let p = Planet(rawValue: 3)
if let p = p {
    switch p {
    case .Mercury:
        print("Mercury")
    case .Venus:
        print("Venus")
    case .Earth:
        print("Mercury")
    case .Mars:
        print("Mars")
    case .Jupiter:
        print("Jupiter")
    case .Saturn:
        print("Saturn")
    case .Uranus:
        print("Uranus")
    case .Neptune:
        print("Neptune")
    }
}

 

9.結構體介紹

結構體的介紹

概念介紹
結構體(struct)是由一系列具備相同類型或不一樣類型的數據構成的數據集合
結構體(struct)指的是一種數據結構
結構體是值類型,在方法中傳遞時是值傳遞
結構的定義格式
struct 結構體名稱 {
    // 屬性和方法
}
結構體的使用

定義&使用結構體
// 初始化結構體
struct Location {
    var x : Double
    var y : Double
}
// 建立結構體
let location = Location(x: 90, y: 90)
結構體的加強

擴充構造函數
默認狀況下建立Location時使用Location(x: x值, y: y值)
可是爲了讓咱們在使用結構體時更加的靈活,swift還能夠對構造函數進行擴充
擴充的注意點
在擴充的構造函數中必須保證成員變量是有值的
擴充的構造函數會覆蓋原有的構造函數
struct Location {
    var x : Double
    var y : Double
    init(x : Double, y : Double) {
        self.x = x
        self.y = y
    }
    init(xyString : String) {
        let strs = xyString.componentsSeparatedByString(",")
        x = Double(strs.first!)!
        y = Double(strs.last!)!
    }
}
let location = Location(x: 100, y: 100)
let location1 = Location(xyString: "100,100")
爲結構體擴充方法
爲了讓結構體使用更加靈活,swift的結構體中能夠擴充方法
例子:爲了Location結構體擴充兩個方法
向水平方向移動的方法
向垂直方向移動的方法
struct Location {
    var x : Double
    var y : Double
    init(x : Double, y : Double) {
        self.x = x
        self.y = y
    }
    init(xyString : String) {
        let strs = xyString.componentsSeparatedByString(",")
        x = Double(strs.first!)!
        y = Double(strs.last!)!
    }
    mutating func moveH(x : Double) {
        self.x += x
    }
    mutating func moveV(y : Double) {
        self.y += y
    }
}
注意:
若是咱們使用的Location不是本身定義的,可是咱們仍舊但願在本身的項目裏擴展Location的操做
Swift也能幫咱們達成,這個機制,叫作extension
extension Location {
    mutating func moveH(x : Double) {
        self.x += x
    }
    mutating func moveV(y : Double) {
        self.y += y
    }
}

 

十、類的定義

主要內容

類的介紹和定義
類的屬性
類的構造函數
一. 類的介紹和定義

Swift也是一門面向對象開發的語言
面向對象的基礎是類,類產生了對象
在Swift中如何定義類呢?
class是Swift中的關鍵字,用於定義類
class 類名 : SuperClass {
    // 定義屬性和方法
}
注意:
定義的類,能夠沒有父類.那麼該類是rootClass
一般狀況下,定義類時.繼承自NSObject(非OC的NSObject)
二. 如何定義類的屬性

類的屬性介紹

Swift中類的屬性有多種
存儲屬性:存儲實例的常量和變量
計算屬性:經過某種方式計算出來的屬性
類屬性:與整個類自身相關的屬性
存儲屬性

存儲屬性是最簡單的屬性,它做爲類實例的一部分,用於存儲常量和變量
能夠給存儲屬性提供一個默認值,也能夠在初始化方法中對其進行初始化
下面是存儲屬性的寫法
age和name都是存儲屬性,用來記錄該學生的年齡和姓名
chineseScore和mathScore也是存儲屬性,用來記錄該學生的語文分數和數學分數
class Student : NSObject {
    // 定義屬性
    // 存儲屬性
    var age : Int = 0
    var name : String?
    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0
}
// 建立學生對象
let stu = Student()
// 給存儲屬性賦值
stu.age = 10
stu.name = "why"
stu.chineseScore = 89.0
stu.mathScore = 98.0
計算屬性

計算屬性並不存儲實際的值,而是提供一個getter和一個可選的setter來間接獲取和設置其它屬性
計算屬性通常只提供getter方法
若是隻提供getter,而不提供setter,則該計算屬性爲只讀屬性,而且能夠省略get{}
下面是計算屬性的寫法
averageScore是計算屬性,經過chineseScore和mathScore計算而來的屬性
在setter方法中有一個newValue變量,是系統指定分配的
class Student : NSObject {
    // 定義屬性
    // 存儲屬性
    var age : Int = 0
    var name : String?
    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0
    // 計算屬性
    var averageScore : Double {
        get {
            return (chineseScore + mathScore) / 2
        }
        // 沒有意義,由於以後獲取值時依然是計算獲得的
        // newValue是系統分配的變量名,內部存儲着新值
        set {
            self.averageScore = newValue
        }
    }
}
// 獲取計算屬性的值
print(stu.averageScore)
類屬性

類屬性是與類相關聯的,而不是與類的實例相關聯
全部的類和實例都共有一份類屬性.所以在某一處修改以後,該類屬性就會被修改
類屬性的設置和修改,須要經過類來完成
下面是類屬性的寫法
類屬性使用static來修飾
courseCount是類屬性,用來記錄學生有多少門課程
class Student : NSObject {
    // 定義屬性
    // 存儲屬性
    var age : Int = 0
    var name : String?
    var chineseScore : Double = 0.0
    var mathScore : Double = 0.0
    // 計算屬性
    var averageScore : Double {
        get {
            return (chineseScore + mathScore) / 2
        }
        // 沒有意義.newValue是系統分配的變量名,內部存儲着新值
        set {
            self.averageScore = newValue
        }
    }
    // 類屬性
    static var corseCount : Int = 0
}
// 設置類屬性的值
Student.corseCount = 3
// 取出類屬性的值
print(Student.corseCount)
監聽屬性的改變

在OC中咱們能夠重寫set方法來監聽屬性的改變
Swift中能夠經過屬性觀察者來監聽和響應屬性值的變化
一般是監聽存儲屬性和類屬性的改變.(對於計算屬性,咱們不須要定義屬性觀察者,由於咱們能夠在計算屬性的setter中直接觀察並響應這種值的變化)
咱們經過設置如下觀察方法來定義觀察者
willSet:在屬性值被存儲以前設置。此時新屬性值做爲一個常量參數被傳入。該參數名默認爲newValue,咱們能夠本身定義該參數名
didSet:在新屬性值被存儲後當即調用。與willSet相同,此時傳入的是屬性的舊值,默認參數名爲oldValue
willSet與didSet只有在屬性第一次被設置時纔會調用,在初始化時,不會去調用這些監聽方法
監聽的方式以下:
監聽age和name的變化
class Person : NSObject {
    var name : String? {
        // 能夠給newValue自定義名稱
        willSet (new){ // 屬性即將改變,還未改變時會調用的方法
            // 在該方法中有一個默認的系統屬性newValue,用於存儲新值
            print(name)
            print(new)
        }
        // 能夠給oldValue自定義名稱
        didSet (old) { // 屬性值已經改變了,會調用的方法
            // 在該方法中有一個默認的系統屬性oldValue,用於存儲舊值
            print(name)
            print(old)
        }
    }
    var age : Int = 0
    var height : Double = 0.0
}
let p : Person = Person()
// 在賦值時,監聽該屬性的改變
// 在OC中是經過重寫set方法
// 在swift中,能夠給屬性添加監聽器
p.name = "why"
//p.name = "yz"

 

十一、類的構造函數

構造函數的介紹

構造函數相似於OC中的初始化方法:init方法
默認狀況下載建立一個類時,必然會調用一個構造函數
即使是沒有編寫任何構造函數,編譯器也會提供一個默認的構造函數。
若是是繼承自NSObject,能夠對父類的構造函數進行重寫
構造函數的基本使用

構造函數的基本使用

類的屬性必須有值
若是不是在定義時初始化值,能夠在構造函數中賦值
class Person: NSObject {
    var name : String
    var age : Int
    // 重寫了NSObject(父類)的構造方法
    override init() {
        name = ""
        age = 0
    }
}
// 建立一個Person對象
let p = Person()
初始化時給屬性賦值

不少時候,咱們在建立一個對象時就會給屬性賦值
能夠自定義構造函數
注意:若是自定義了構造函數,會覆蓋init()方法.即不在有默認的構造函數
class Person: NSObject {
    var name : String
    var age : Int
    // 自定義構造函數,會覆蓋init()函數
    init(name : String, age : Int) {
        self.name = name
        self.age = age
    }
}
// 建立一個Person對象
let p = Person(name: "why", age: 18)
字典轉模型(初始化時傳入字典)

真實建立對象時,更多的是將字典轉成模型
注意:
去字典中取出的是NSObject,任意類型.
能夠經過as!轉成須要的類型,再賦值(不能夠直接賦值)
class Person: NSObject {
    var name : String
    var age : Int
    // 自定義構造函數,會覆蓋init()函數
    init(dict : [String : NSObject]) {
        name = dict["name"] as! String
        age = dict["age"] as! Int
    }
}
// 建立一個Person對象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)
字典轉模型(利用KVC轉化)

利用KVC字典轉模型會更加方便
注意:
KVC並不能保證會給全部的屬性賦值
所以屬性須要有默認值
基本數據類型默認值設置爲0
對象或者結構體類型定義爲可選類型便可(可選類型沒有賦值前爲nil)
class Person: NSObject {
    // 結構體或者類的類型,必須是可選類型.由於不能保證必定會賦值
    var name : String?
    // 基本數據類型不能是可選類型,不然KVC沒法轉化
    var age : Int = 0
    // 自定義構造函數,會覆蓋init()函數
    init(dict : [String : NSObject]) {
        // 必須先初始化對象
        super.init()
        // 調用對象的KVC方法字典轉模型
        setValuesForKeysWithDictionary(dict)
    }
}
// 建立一個Person對象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)

 

十二、類的析構函數

析構函數

Swift 會自動釋放再也不須要的實例以釋放資源
Swift 經過自動引用計數(ARC)處理實例的內存管理
當引用計數爲0時,系統會自動調用析構函數(不能夠手動調用)
一般在析構函數中釋放一些資源(如移除通知等操做)
析構函數的寫法
deinit {
    // 執行析構過程
}
示例練習

class Person {
    var name : String
    var age : Int
    init(name : String, age : Int) {
        self.name = name
        self.age = age
    }
    deinit {
        print("Person-deinit")
    }
}
var p : Person? = Person(name: "why", age: 18)
p = nil

 

1三、循環引用解決

工做機制

Swift和OC同樣,採用自動引用計數來管理內容
當有一個強引用指向某一個動向時,該對象的引用計數會自動+1
當該強引用消失時,引用計數會自動-1
當引用計數爲0時,該對象會被銷燬
循環引用

在一般狀況下,ARC是會自動幫助咱們管理內存的
可是在開發中咱們常常會出現循環引用的問題,好比下面的示例
Student對Book對象有一個強引用
而Book對Student有一個強引用
在兩個對象都指向nil時,依然不會被銷燬,就造成了循環引用
// 1.建立類
class Student {
    var book : Book?
    deinit {
        print("Student -- deinit")
    }
}
class Book {
    var owner : Student?
    deinit {
        print("Book -- deinit")
    }
}
// 2.建立對象
var stu : Student? = Student()
var book : Book? = Book()
// 3.相互引用
stu?.book = book
book?.owner = stu
// 4.對象置nil
stu = nil
book = nil
解決方案
swift提供了兩種解決方案
weak : 和OC中的__weak同樣是一個弱引用.當指向的對象銷燬時,會自動將指針指向nil
unowned : 和OC中的__unsafe_unretained.當對象銷燬時依然指向原來的位置(容易引發野指針)
// 1.建立類
class Student {
    weak var book : Book?
    // unowned var book : Book = Book()
    deinit {
        print("Student -- deinit")
    }
}
class Book {
    var owner : Student?
    deinit {
        print("Book -- deinit")
    }
}
// 2.建立對象
var stu : Student? = Student()
var book : Book? = Book()
// 3.相互引用
stu?.book = book!
book?.owner = stu
// 4.對象置nil
stu = nil
book = nil

 

14.可選鏈的使用

可選連的概念

它的可選性體現於請求或調用的目標當前可能爲空(nil)
若是可選的目標有值,那麼調用就會成功;
若是選擇的目標爲空(nil),則這種調用將返回空(nil)
屢次調用被連接在一塊兒造成一個鏈,若是任何一個節點爲空(nil)將致使整個鏈失效。
可選鏈的使用
在可選類型後面放一個問號,能夠定義一個可選鏈。
這一點很像在可選值後面放一個歎號來強制拆得其封包內的值
它們的主要的區別在於當可選值爲空時可選鏈即刻失敗
然而通常的強制解析將會引起運行時錯誤。
由於可選鏈的結果可能爲nil,可能有值.所以它的返回值是一個可選類型.
能夠經過判斷返回是否有值來判斷是否調用成功
有值,說明調用成功
爲nil,說明調用失敗
可選鏈的示例

從可選鏈中取值
示例描述: 人(Person)有一個狗(Dog),狗(Dog)有一個玩具(Toy),玩具備價格(price)
使用代碼描述上述信息
// 1.定義類
class Person {
    var name : String
    var dog : Dog?
    init(name : String) {
        self.name = name
    }
}
class Dog {
    var color : UIColor
    var toy : Toy?
    init(color : UIColor) {
        self.color = color
    }
    func runing() {
        print("跑起來")
    }
}
class Toy {
    var price : Double = 0.0
}
// 2.建立對象,而且設置對象之間的關係
// 2.1.建立對象
let person = Person(name: "小明")
let dog = Dog(color: UIColor.yellow)
let toy = Toy()
toy.price = 100.0
// 2.2.設置對象之間的關係
person.dog = dog
dog.toy = toy
需求:獲取小明的大黃寵物的玩具價格
取出的值爲可選類型,由於可選鏈中有一個可選類型爲nil,則返回nil
所以結果可能有值,可能爲nil.所以是一個可選類型
let price = person.dog?.toy?.price
print(price) // Optional(100.0)\n
需求:給小明的大黃一個新的玩具
至關於給可選類型賦值
person.dog?.toy = Toy()
需求:讓小明的狗跑起來
若是可選類型有值,則會執行該方法
若是可選類型爲nil,則該方法不會執行
person.dog?.runing()

 

1五、協議的使用

協議的格式

協議的定義方式與類,結構體,枚舉的定義都很是類似
protocol SomeProtocol {
    // 協議方法
}
遵照協議的格式
class SomeClass: SomeSuperClass, FirstProtocol,             AnotherProtocol {
    // 類的內容
    // 實現協議中的方法
}
協議的基本使用

定義協議和遵照協議
// 1.定義協議
protocol SportProtocol {
    func playBasketball()
    func playFootball()
}
// 2.遵照協議
// 注意:默認狀況下在swift中全部的協議方法都是必須實現的,若是不實現,則編譯器會報錯
class Person : SportProtocol {
    var name : String?
    var age : Int = 0
    // 實現協議中的方法
    func playBasketball() {
        print("人在打籃球")
    }
    func playFootball() {
        print("人在踢足球")
    }
}
協議之間的繼承
protocol CrazySportProtocol {
    func jumping()
}
protocol SportProtocol : CrazySportProtocol {
    func playBasketball()
    func playFootball()
}
代理設計模式

協議繼承用於代理設計模式
protocol BuyTicketProtocol {
    func buyTicket()
}
class Person {
    // 1.定義協議屬性
    var delegate : BuyTicketProtocol
    // 2.自定義構造函數
    init (delegate : BuyTicketProtocol) {
        self.delegate = delegate
    }
    // 3.行爲
    func goToBeijing() {
        delegate.buyTicket()
    }
}
class HuangNiu: BuyTicketProtocol {
    func buyTicket() {
        print("買了一張火車票")
    }
}
let p = Person(delegate: HuangNiu())
p.goToBeijing()
協議中方法的可選

// 1.定義協議
@objc
protocol SportProtocol {
    func playBasketball()
    optional func playFootball()
}
// 2.遵照協議
class Person : SportProtocol {
    var name : String?
    var age : Int = 0
    // 實現協議中的方法
    @objc func playBasketball() {
        print("人在打籃球")
    }
}

 

 

3、swift

1.閉包的使用

閉包的介紹

閉包和OC中的block很是類似
OC中的block是匿名的函數
Swift中的閉包是一個特殊的函數
block和閉包都常常用於回調
注意:閉包和block同樣,第一次使用時可能不習慣它的語法,能夠先按照使用簡單的閉包,隨着學習的深刻,慢慢掌握其靈活的運用方法.
閉包的使用

block的用法回顧

定義網絡請求的類
@interface HttpTool : NSObject
- (void)loadRequest:(void (^)())callBackBlock;
@end
@implementation HttpTool
- (void)loadRequest:(void (^)())callBackBlock
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"加載網絡數據:%@", [NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            callBackBlock();
        });
    });
}
@end
進行網絡請求,請求到數據後利用block進行回調
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.httpTool loadRequest:^{
        NSLog(@"主線程中,將數據回調.%@", [NSThread currentThread]);
    }];
}
block寫法總結:
block的寫法:
    類型:
    返回值(^block的名稱)(block的參數)
    值:
    ^(參數列表) {
        // 執行的代碼
    };
使用閉包代替block

定義網絡請求的類
class HttpTools: NSObject {
    func requestData(finishedCallback : @escaping (_ jsonData : String, _ age : Int) -> ()) {
        // 1.建立全局隊列, 發送異步請求
        DispatchQueue.global().async {
            print("發送網絡請求:\(Thread.current)")
            DispatchQueue.main.async {
                print("回調主線程:\(Thread.current)")
                finishedCallback("123", 30)
            }
        }
    }
}
進行網絡請求,請求到數據後利用閉包進行回調
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        httpTools.requestData { (jsonData :String, age : Int) in
            print("回到控制器,獲取到數據")
        }
    }
閉包寫法總結:
閉包的寫法:
    類型:(形參列表)->(返回值)
    技巧:初學者定義閉包類型,直接寫()->().再填充參數和返回值
    值:
    {
        (形參) -> 返回值類型 in
        // 執行代碼
    }
尾隨閉包寫法:
若是閉包是函數的最後一個參數,則能夠將閉包寫在()後面
若是函數只有一個參數,而且這個參數是閉包,那麼()能夠不寫
    httpTool.loadRequest() {
        print("回到主線程", NSThread.currentThread());
    }
    // 開發中建議該寫法
    httpTool.loadRequest {
        print("回到主線程", NSThread.currentThread());
    }
閉包的循環引用

若是在HttpTool中有對閉包進行強引用,則會造成循環引用
補充:在Swift中檢測一個對象是否銷燬,能夠實現對象的deinit函數
    // 析構函數(至關於OC中dealloc方法)
    deinit {
        print("ViewController----deinit")
    }
循環引用的(實現)
該實現是爲了產生循環引用,而產生的循環引用
class HttpTools: NSObject {
    var finishedCallback : ((_ jsonData : String, _ age : Int) -> ())?
    func requestData(finishedCallback : @escaping (_ jsonData : String, _ age : Int) -> ()) {
        self.finishedCallback = finishedCallback
        // 1.建立全局隊列, 發送異步請求
        DispatchQueue.global().async {
            print("發送網絡請求:\(Thread.current)")
            DispatchQueue.main.async {
                print("回調主線程:\(Thread.current)")
                finishedCallback("123", 30)
            }
        }
    }
}
swift中解決循環引用的方式
方案一:
使用weak,對當前控制器使用弱引用
可是由於self可能有值也可能沒有值,所以weakSelf是一個可選類型,在真正使用時能夠對其強制解包(該處強制解包沒有問題,由於控制器必定存在,不然沒法調用所在函數)
    // 解決方案一:
    weak var weakSelf = self
    httpTool.loadData {
        print("加載數據完成,更新界面:", NSThread.currentThread())
        weakSelf!.view.backgroundColor = UIColor.redColor()
    }
方案二:
和方案一類型,只是書寫方式更加簡單
能夠寫在閉包中,而且在閉包中用到的self都是弱引用
    httpTool.loadData {[weak self] () -> () in
        print("加載數據完成,更新界面:", NSThread.currentThread())
        self!.view.backgroundColor = UIColor.redColor()
    }
方案三:(經常使用)
使用關鍵字unowned
從行爲上來講 unowned 更像OC中的 unsafe_unretained
unowned 表示:即便它原來引用的對象被釋放了,仍然會保持對被已經釋放了的對象的一個 「無效的」 引用,它不能是 Optional 值,也不會被指向 nil
httpTool.loadData {[unowned self] () -> () in
        print("加載數據完成,更新界面:", NSThread.currentThread())
        self.view.backgroundColor = UIColor.redColor()
    }

 

2.懶加載的使用

懶加載的介紹

swift中也有懶加載的方式
(蘋果的設計思想:但願全部的對象在使用時才真正加載到內存中)
和OC不一樣的是swift有專門的關鍵字來實現懶加載
lazy關鍵字能夠用於定義某一個屬性懶加載
懶加載的使用

格式
lazy var 變量: 類型 = { 建立變量代碼 }()
懶加載的使用
    // 懶加載的本質是,在第一次使用的時候執行閉包,將閉包的返回值賦值給屬性
    // lazy的做用是隻會賦值一次
    lazy var array : [String] = {
        () -> [String] in
        return ["why", "lmj", "lnj"]
    }()

 

3.訪問權限

swift中的訪問權限

Swift 中的訪問控制模型基於模塊和源文件這兩個概念
internal : 在本模塊中均可以進行訪問
fileprivate : 在當前源文件中能夠訪
private : 在當前class中能夠訪問(extension中也不能夠訪問)
open : 在其餘模塊中能夠訪問
相關文章
相關標籤/搜索