Swift-知識點

協(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)建變量代碼}()
  • 懶加載的使用
    // 懶加載的本質(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

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


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

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

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