協(xié)議
協(xié)議支持多繼承
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 類的內(nèi)容
// 實現(xiàn)協(xié)議中的方法
}
- 類 結(jié)構(gòu)體 枚舉都可以遵守協(xié)議
// 1.定義協(xié)議
protocol SportProtocol {
func playBasketball()
func playFootball()
}
// 2.遵守協(xié)議
// 注意:默認情況下在swift中所有的協(xié)議方法都是必須實現(xiàn)的,如果不實現(xiàn),則編譯器會報錯
class Person : SportProtocol {
var name : String?
var age : Int = 0
// 實現(xiàn)協(xié)議中的方法
func playBasketball() {
print("人在打籃球")
}
func playFootball() {
print("人在踢足球")
}
}
協(xié)議之間的繼承
protocol CrazySportProtocol {
func jumping()
}
protocol SportProtocol : CrazySportProtocol {
func playBasketball()
func playFootball()
}
協(xié)議繼承用于代理設計模式
protocol BuyTicketProtocol {
func buyTicket()
}
class Person {
// 1.定義協(xié)議屬性
var delegate : BuyTicketProtocol
// 2.自定義構(gòu)造函數(shù)
init (delegate : BuyTicketProtocol) {
self.delegate = delegate
}
// 3.行為
func goToBeijing() {
delegate.buyTicket()
}
}
class HuangNiu: BuyTicketProtocol {
func buyTicket() {
print("買了一張火車票")
}
}
let p = Person(delegate: HuangNiu())
p.goToBeijing()
- 代理屬性,一般都是使用weak修飾
- weak修飾的必須是類類型的對象
- 一般要求,協(xié)議繼承自NSObjectProtocol / class
在Swift中,如果遵守了一個協(xié)議,必須要實現(xiàn),協(xié)議里面所有的方法
協(xié)議可選是OC的特性
- @objc 修飾協(xié)議
- @objc optional 修飾方法
// 1.定義協(xié)議
@objc
protocol SportProtocol {
func playBasketball()
@objc optional func playFootball()
}
// 2.遵守協(xié)議
class Person : SportProtocol {
var name : String?
var age : Int = 0
// 實現(xiàn)協(xié)議中的方法
@objc func playBasketball() {
print("人在打籃球")
}
}
泛型
簡單的理解泛型就是一個"泛化"的類型,并不特指某一個具體的類型
- 泛型的使用
-
作為函數(shù)的參數(shù)或返回值
泛型作為返回值 - 泛型與類型的結(jié)合
-
與結(jié)構(gòu)體的結(jié)合
與結(jié)構(gòu)體結(jié)合 -
與類的結(jié)合
與類結(jié)合 -
與協(xié)議的關(guān)聯(lián)
與協(xié)議關(guān)聯(lián)
-
- 泛型與where子句結(jié)合使用
- 與where子句結(jié)合使用
-
閉包
- 閉包與OC中的Block非常相似
- OC中的block是匿名的函數(shù)
- Swift中的閉包是一個特殊的函數(shù)
- block和閉包都是經(jīng)常用于回調(diào)
block的用法回顧
* 定義網(wǎng)絡請求的類
@interface HttpTool : NSObject
- (void)loadRequest:(void (^)())callBackBlock;
@end
@implementation HttpTool
- (void)loadRequest:(void (^)())callBackBlock
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"加載網(wǎng)絡數(shù)據(jù):%@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
callBackBlock();
});
});
}
@end
* 進行網(wǎng)絡請求,請求到數(shù)據(jù)后利用block進行回調(diào)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self.httpTool loadRequest:^{
NSLog(@"主線程中,將數(shù)據(jù)回調(diào).%@", [NSThread currentThread]);
}];
}
閉包格式
類型 類型:(形參列表)->(返回值)
{
值 (形參) -> 返回值類型 in
執(zhí)行代碼
}
使用閉包代替block
* 定義網(wǎng)絡請求的類
class HttpTool: NSObject {
func loadRequest(callBack : ()->()){
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("加載數(shù)據(jù)", [NSThread.currentThread()])
dispatch_async(dispatch_get_main_queue(), { () -> Void in
callBack()
})
}
}
}
* 進行網(wǎng)絡請求,請求到數(shù)據(jù)后利用閉包進行回調(diào)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// 網(wǎng)絡請求
httpTool.loadRequest ({ () -> () in
print("回到主線程", NSThread.currentThread());
})
}
閉包的簡寫
如果閉包沒有參數(shù) in和in之間的內(nèi)容可以省略
httpTool.loadRequest({
print("回到主線程", NSThread.currentThread());
})
尾隨閉包
- 寫法
- 如果閉包是函數(shù)的最后一個參數(shù),則可以將閉包寫在()后面
- 如果函數(shù)只有一個參數(shù),并且這個參數(shù)是閉包,那么()可以不寫
httpTool.loadRequest() {
print("回到主線程", NSThread.currentThread());
}
// 開發(fā)中建議該寫法
httpTool.loadRequest {
print("回到主線程", NSThread.currentThread());
}
如果在HttpTool中有對閉包進行強引用,則會形成循環(huán)引用
class HttpTool: NSObject {
// 定義屬性,來強引用傳入的閉包
var callBack : (()->())?
func loadRequest(callBack : ()->()){
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("加載數(shù)據(jù)", [NSThread.currentThread()])
dispatch_async(dispatch_get_main_queue(), { () -> Void in
callBack()
})
}
self.callBack = callBack
}
}
在Swift中檢測一個對象是否銷毀,可以實現(xiàn)對象的deinit函數(shù)
循環(huán)引用解決方案
-
方案一
- 使用weak,對self使用所引用
- 但是self可能有值也可能沒有值,因為weakSelf是一個可選類型,正真正使用時可以對其強制解包(該處強制捷豹沒有問題,因為控制器一定存在,否則無法調(diào)用所在函數(shù))
// 解決方案一: weak var weakSelf = self httpTool.loadData { print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) weakSelf!.view.backgroundColor = UIColor.redColor() } -
方案二
-
可以寫在閉包中,并且閉包中用到的self都是弱引用
httpTool.loadData {[weak self] () -> () in print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) self!.view.backgroundColor = UIColor.redColor()
}
``` -
-
方案三
- 使用關(guān)鍵字'unowned'
- 從行為上來說 unowned 更像OC中的unsafe_unretained
- unowned表示:即使它原來引用的對象被釋放了,仍然會保持對被已經(jīng)釋放了的對象的一個"無效的"引用,它不能是 Optional值,也不會被指向nil
httpTool.loadData {[unowned self] () -> () in print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) self.view.backgroundColor = UIColor.redColor() }逃逸閉包 非逃逸閉包
// @escaping 逃逸閉包 // 可以被其他對象引用 -- 逃逸閉包 // 默認情況下, 閉包, 是不能被其他對象引用 -- 非逃逸閉包
懶加載
- 懶加載介紹
- 和OC不同的是swift有專門的關(guān)鍵字來實現(xiàn)懶加載
- lazy關(guān)鍵字可以用于定義某一個屬性懶加載
- 格式
- lazy var 變量:類型 = 函數(shù)名() 構(gòu)造函數(shù)
自定義函數(shù) - lazy var 變量:類型 = {創(chuàng)建變量代碼}()
- lazy var 變量:類型 = 函數(shù)名() 構(gòu)造函數(shù)
- 懶加載的使用
// 懶加載的本質(zhì)是,在第一次使用的時候執(zhí)行閉包,將閉包的返回值賦值給屬性
// lazy的作用是只會賦值一次
lazy var array : [String] = {
() -> [String] in
return ["sz", "lmj", "lnj"]
}()
注釋
-
單行注釋
- 單行注釋以 // 作為起始標記
- // 注釋內(nèi)容
-
多行注釋
- 以/*開頭
- 以*/結(jié)尾
- 和C語言多行注釋不同的是,Swift的多行注釋可以嵌套多行注釋
/* 內(nèi)容 /* 內(nèi)容 */ 內(nèi)容 */ -
文檔注釋
-
格式 1
/** 方法的含義描述 - parameter path: 路徑 - throws: 拋出異常 - returns: 返回值 */ 格式 2
/// 方法的功能描述 /// - parameter a 參數(shù)a的含義描述 /// - parameter b 參數(shù)b的含義描述 /// - throws: 異常描述 /// - returns: 返回值描述快捷鍵 command + option + /
格式 3
/// 方法的功能描述 /// * 描述1 /// * 描述2 /** 描述 描述 */ /// - parameter a: 參數(shù)a的含義描述 /// - parameter b: 參數(shù)b的含義描述 /// - throws: 異常描述 /// - returns: 返回值描述 -
-
分組注釋
- Swift中不可以再使用 '#pragma mark - '
- 如果打算對代碼進行分組可以使用 '//MARK:-'方式
- MARK : //MARK: -
- TODO : //TODO: - 需要做
- FIXME : //FIXME:解決bug
開啟分組注釋
因為默認的話 TODO 跟 FIXME 是沒有開啟的,所以需要我們手動開啟
步驟 一

步驟二

開啟注釋代碼 直接復制粘貼就好了
TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \\( -name "*.swift" \\) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\\$" | perl -p -e "s/($TAGS)/ warning: \\$1/"
優(yōu)點:

訪問權(quán)限
OC中的訪問權(quán)限
@private:作用范圍只能在自身類
@protected:作用范圍在自身類和繼承自己的子類,什么都不寫,默認是此屬性。
@public:作用范圍最大,在任何地方
@package:本包內(nèi)使用,跨包不可以
- 注意
- 只是用來修飾成員變量,無法修飾方法
- @interface中的聲明的成員變量默認是public,@implatation中聲明的成員變量默認是private
Swift中的訪問控制模型基于模塊和源文件,類這三個概念
internal:在本模塊中都可以進行訪問 默認的 子類可以繼承
private:當前類私有
fileprivate:在當前源文件中可以訪問
public:在其他模塊中可以訪問,但不能被override,如果修飾類,則無法繼承
open:在其他模塊中可以訪問,并且可以被override,如果修飾類,可以繼承
- 注意
- Swift訪問權(quán)限,作用與類,屬性,方法等
- Swift中的訪問級別遵守一個基本原則:不可以在某個實體中定義訪問級別更高的實體
方法拋出異常
-
異常的介紹
- 只要我們在編程,就一定要面對錯誤處理的問題.
- Swift在設計的時候就盡可能讓我們明確感知錯誤.明確處理錯誤 *比如:只有使用Optional才能處理空值
- 如何描述一個錯誤?
- 在Swift里,任何一個遵從Error protocol的類型,都可以用于描述錯誤
- Error是一個空的protocol,它唯一的功能,就是告訴Swift編譯器,某個類用來表示一個錯誤.
- 通常,我們使用一個enum來定義各種錯誤的可能性
-
異常的示例
-
當我們調(diào)用方法獲取結(jié)果為nil時,你并不能確定到底參數(shù)什么錯誤得到了nil
func readFileContent(filePath : String) -> String? {
// 1.filePath為""
if filePath == "" {
return nil
}// 2.filepath有值,但是沒有對應的文件 if filePath != "/User/Desktop/123.plist" { return nil } // 3.取出其中的內(nèi)容 return "123" } readFileContent("abc") ```使用異常對上述方法進行改進
// 1.定義異常 enum FileReadError : Error { case FileISNull case FileNotFound } // 2.改進方法,讓方法拋出異常 func readFileContent(filePath : String) throws -> String { // 1.filePath為"" if filePath == "" { throw FileReadError.FileISNull } // 2.filepath有值,但是沒有對應的文件 if filePath != "/User/Desktop/123.plist" { throw FileReadError.FileISNull } // 3.取出其中的內(nèi)容 return "123" } -
-
處理異常的方式
- 1 try方式,需要手動處理異常
do { let result = try readFileContent("abc") } catch { print(error) }- 2 try?方式,不處理異常,如果出現(xiàn)了異常,則返回一個nil,沒有異常則返回對應的值
// 最終返回結(jié)果為一個可選類型 let result = try? readFileContent("abc")- try!方法,告訴系統(tǒng)改方法沒有異常
// 注意:如果出現(xiàn)了異常,則程序會崩潰 try! readFileContent("abc")
Swift調(diào)用OC
方式一 創(chuàng)建OC文件時提示,點擊Create Bridging Header

方式二

導入橋接文件的全路徑

在橋接文件中,直接導入OC的頭文件,就可以使用了

OC調(diào)用Swift


- 注意
- 如果想讓Swift類/方法/屬性, 在OC中使用; 需要使用public關(guān)鍵字對類/方法/屬性等進行修飾
- 如果是類, 必須繼承自NSObject
-
如果是協(xié)議
-





