姓名:謝艾芳? 學號:16040410073
Swift基礎知識4(接上一篇)
轉自http://www.lxweimin.com/p/02ab8c6c1f9f
〖嵌牛導讀〗Swift 語言由蘋果公司在 2014 年推出,用來撰寫 OS X 和 iOS 應用程序,Swift語言讓應用開發更簡單、更快、更穩定,確保最終應用有著更好的質量
〖嵌牛鼻子〗Swift基礎知識 Swift的編程技巧和方法
〖嵌牛提問〗如何簡單學習Swift基本編程語言?
〖嵌牛正文〗
十一、類的使用
1、類的介紹和定義
Swift也是一門面向對象開發的語言,面向對象的基礎是類,類產生了對象,class是Swift中的關鍵字,用于定義類
定義的類,可以沒有父類.那么該類是rootClass,通常情況下,定義類時,繼承自NSObject(非OC的NSObject)
class 類名 : SuperClass {
? ? // 定義屬性和方法
}
2、定義類的屬性
Swift中類的屬性有多種:存儲屬性,存儲實例的常量和變量;計算屬性,通過某種方式計算出來的屬性;類屬性,與整個類自身相關的屬性
① 存儲屬性
存儲屬性是最簡單的屬性,它作為類實例的一部分,用于存儲常量和變量,可以給存儲屬性提供一個默認值,也可以在初始化方法中對其進行初始化
// 給存儲屬性賦值
stu.age = 10
stu.name = "xiaoming"
stu.chineseScore = 89.0
stu.mathScore = 98.0
② 計算屬性
計算屬性并不存儲實際的值,而是提供一個getter和一個可選的setter來間接獲取和設置其它屬性,計算屬性一般只提供getter方法,如果只提供getter,而不提供setter,則該計算屬性為只讀屬性,并且可以省略get{}
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來修飾
class Student : NSObject {
? ? // 類屬性
? ? static var corseCount : Int = 0
}
// 設置類屬性的值
Student.corseCount = 3
// 取出類屬性的值
print(Student.corseCount)
④ 監聽屬性的改變
在OC中我們可以重寫set方法來監聽屬性的改變,在Swift中可以通過屬性觀察者來監聽和響應屬性值的變化,通常是監聽存儲屬性和類屬性的改變,(對于計算屬性,我們不需要定義屬性觀察者,因為我們可以在計算屬性的setter中直接觀察并響應這種值的變化)
willSet:在屬性值被存儲之前設置,此時新屬性值作為一個常量參數被傳入,該參數名默認為newValue,我們可以自己定義該參數名;didSet:在新屬性值被存儲后立即調用,與willSet相同,此時傳入的是屬性的舊值,默認參數名為oldValue;
willSet與didSet只有在屬性第一次被設置時才會調用,在初始化時,不會去調用這些監聽方法
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 = "xiaoming"
十二、類的構造函數
構造函數類似于OC中的初始化方法init方法,默認情況下載創建一個類時,必然會調用一個構造函數,即便是沒有編寫任何構造函數,編譯器也會提供一個默認的構造函數,如果是繼承自NSObject,可以對父類的構造函數進行重寫
1、構造函數的基本使用
① 類的屬性必須有值,如果不是在定義時初始化值,可以在構造函數中賦值
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: "xiaoming", age: 18)
③ 字典轉模型(初始化時傳入字典)
例1
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" : "xiaoming", "age" : 18]
let p = Person(dict: dict)
例2
利用KVC字典轉模型
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" : "xiaoming", "age" : 18]
let p = Person(dict: dict)
十三、閉包
Swift閉包和OC中的block非常相似,OC中的block是匿名的函數,Swift中的閉包是一個特殊的函數,block和閉包都經常用于回調
1、OC中Block的使用
首先介紹一下OC中Block寫法
① 第一種Block方式
@property (nonatomic, copy) void(^callBack)(NSString *name);
callBack 是block對象
回調方法
if(_callBack){
_callBack(name)
}
② 第二種Block方式
typedef void(^CallBack)(NSString *str);
@property (nonatomic, copy) CallBack callback;
callback是block對象
回調方法
if(_callBack){
_callBack(name)
}
③ 第三種Block方式
- (void)setUpWith:(void(^)(NSString *str))callback;
callback是block對象
回調方法
if(_callBack){
_callBack(name)
}
總結
Block的寫法:
? ? 類型:
? ? 返回值類型(^block的名稱)(block的參數)
? ? 值:
? ? ^(參數列表) {
? ? ? ? // 執行的代碼
? ? };
2、Swift中閉包的使用
① 第一種閉包方式
var callBack : (()->())?
② 第二種閉包方式
func loadRequest(callBack : ()->()){
? ? ? ? ? ? ? ? callBack()
? ? }
總結
閉包的寫法:
? callBack: (形參列表) -> (返回值類型)
? ? 類型:(形參列表) -> (返回值類型)
? ? 值:
? ? {
? ? ? ? (形參) -> 返回值類型 in
? ? ? ? // 執行代碼
? ? }
閉包的簡寫,如果閉包沒有參數,沒有返回值,in和in之前的內容可以省略
尾隨閉包寫法
① 如果閉包是函數的最后一個參數,則可以將閉包寫在()后面
? ? httpTool.loadRequest() {
? ? ? ? print("回到主線程", NSThread.currentThread());
? ? }
② 如果函數只有一個參數,并且這個參數是閉包,那么()可以不寫
? ? // 開發中建議該寫法
? ? httpTool.loadRequest {
? ? ? ? print("回到主線程", NSThread.currentThread());
? ? }
3、閉包的循環引用
如果在HttpTool中有對閉包進行強引用,則會形成循環引用,在Swift中檢測一個對象是否銷毀,可以實現對象的deinit函數
// 析構函數(相當于OC中dealloc方法)
? ? deinit {
? ? ? ? print("ViewController----deinit")
? ? }
4、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()
? ? }
十四、懶加載
swift中也有懶加載的方式,希望所有的對象在使用時才真正加載到內存中,和OC不同的是swift有專門的關鍵字來實現懶加載,lazy關鍵字可以用于定義某一個屬性懶加載
1、懶加載普通方式
lazy var 變量:類型 = 系統類()
lazy var button:UIButton = UIButton()
2、懶加載升級方式
lazy var array : [String] = {
? ? ? ? () -> [String] in
? ? ? ? return ["xiaoming", "xl", "lisi"]
? ? }()