[Swift Tips 讀書筆記]從 Objective-C 到 Swift(二)

  1. @objc 和 dynamic
  1. 可選協(xié)議和協(xié)議擴(kuò)展
  2. 內(nèi)存管理,weak 和 unowned
  3. @autoreleasepool
  4. 值類型和引?類型
  5. String 還是 NSString

--

@objc 和 dynamic

  • swift工程調(diào)用OC代碼
    在一個(gè)swift工程里使用OC的代碼,需要導(dǎo)入一個(gè)文件 'OCToSwift-Bridging-Header.h' (OCToSwift是工程名)。在這個(gè)頭文件里面導(dǎo)入OC代碼的頭文件,這樣就可以在swift里直接調(diào)用OC代碼了。


    swift工程里創(chuàng)建OC文件,Xcode 提示創(chuàng)建橋頭文件
  • OC工程調(diào)用Swift代碼

    // 如果調(diào)用一個(gè)swift寫的第三方庫,二者不在同一個(gè)target里
    @import SwiftVender; //引入SwiftVender模塊
    
    // 如果調(diào)用同一個(gè)工程里的swift文件。
    #import "OCProject-Swift.h"http://導(dǎo)入頭文件 
    

OC 是動態(tài)語言,類型的確定和方法的調(diào)用等都是等到運(yùn)行時(shí)去確定的,但是swift為了追求性能,如果沒有特殊需要,是在編譯時(shí)就確定的,運(yùn)行時(shí)候不用再查找,而是可以直接使用。

這就導(dǎo)致一個(gè)問題,如果用OC代碼調(diào)用純swift類型時(shí)候,就會因?yàn)檎也坏叫枰男畔⒍ ?/p>

解決方法就是,在swift類型文件中,在需要暴露給OC的任何地方(類、屬性、方法)前都加上 @objc 修飾符。(這個(gè)步驟,針對不是繼承自NSObject類的class,如果一個(gè)類繼承自NSObject,swift會默認(rèn)自動給非private的地方加上@objc。如果要使用private方法或?qū)傩缘膭討B(tài)話方法,要手動加@objc。)

@objc 的另一個(gè)作用體現(xiàn)在OC側(cè)。一個(gè)swift類名或者方法名時(shí)漢字的時(shí)候。在OC里面調(diào)用的時(shí)候用@objc將其轉(zhuǎn)為ASCII碼。

@objc修飾不意味著這個(gè)方法或?qū)傩詴討B(tài)派發(fā),如果想要使用動態(tài)的特性,用dynamic修飾。

--

可選協(xié)議和協(xié)議擴(kuò)展

屏幕快照_2017-06-05_15_34_38.png
  • OC里的協(xié)議方法,可以通過關(guān)鍵字@required 和 @optional 修飾,如果一個(gè)方法用 @optional 修飾,繼承這個(gè)協(xié)議的類就可以選擇不實(shí)現(xiàn)方法。Swift里面協(xié)議的所有方法都是必須實(shí)現(xiàn)的。

  • swift 實(shí)現(xiàn)可選協(xié)議的兩種方式

    • 方式一
      用 @objc 修飾協(xié)議和可選的協(xié)議方法,并且用optional修飾可選的協(xié)議方法。

      @objc protocol ViewControllerDelegate {
      //必須實(shí)現(xiàn)的方法0
      func delegateMethod0(name: String)
      //可選實(shí)現(xiàn)的方法1
      @objc optional func delegateMethod1()
      //可選實(shí)現(xiàn)的方法2 。swift里面optional修飾需要在每個(gè)可選的方法前面加,而不是像OC里面只寫一遍 @optional 就行了
      @objc optional func delegateMethod2()
      
      }
      

    使用 @objc 修飾的 protocol 就只能被 class 實(shí)現(xiàn)了,struct 和 enum 就不能實(shí)現(xiàn)協(xié)議里的方法了。

    • 方式二
      利用 protocol extension 的方式,給出協(xié)議的默認(rèn)實(shí)現(xiàn)。這樣在繼承這個(gè)協(xié)議的類中協(xié)議方法就是可選實(shí)現(xiàn)的了。

      protocol ViewControllerDelegate {
        //必須實(shí)現(xiàn)
        func delegateMethod0(name: String)
        //可選實(shí)現(xiàn)
        func delegateMethod1()
      }
      
      extension ViewControllerDelegate {
        func delegateMethod1() {
            print("可選實(shí)現(xiàn)方法1")
        }
      }
      
      class ViewController: UIViewController,ViewControllerDelegate {
        func delegateMethod0(name: String) {
            print("必須實(shí)現(xiàn)的協(xié)議方法")
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            self.delegateMethod0(name: "fsad")
           //ViewController 沒有實(shí)現(xiàn)方法delegateMethod1,這里調(diào)用的是extension里的實(shí)現(xiàn)
            self.delegateMethod1() 
          }
      }
      

--

內(nèi)存管理,weak 和 unowned

swift 的內(nèi)存管理也是遵循ARC原則,進(jìn)行自動內(nèi)存管理。

  • 在swift里防止循環(huán)引用
    用 weak 修飾,表示不希望持有這個(gè)實(shí)例。

    class ClassA: NSObject {
    weak var b : ClassB?  //用weak修飾
    deinit {
            print("A deinit")
        } 
    }
    
    class ClassB: NSObject {
      var a: ClassA?
      deinit {
          print("B deinit")
         }
    }
    
     // ClassA 中 ,聲明屬性b的時(shí)候用 weak 修飾。表示不希望持有 b,整個(gè)環(huán)境中,就沒有對b這個(gè)實(shí)例的持有了。這個(gè)實(shí)例b就可以釋放了,在b釋放的時(shí)候,他對a的持有也會釋放。就沒有循環(huán)引用了。
     let a = ClassA()
     let b = ClassB()
      
      a.b = b
      b.a = a
    
  • weak 和 unowned 的區(qū)別

    unowned 更像OC里的 unsafe_unretained,weak 像 OC 里的weak。

unowned 設(shè)置以后,即使它原來引用的內(nèi)容B已經(jīng)被釋放了,它仍然保存一個(gè)指向原來內(nèi)容B的無效引用。它不能為 Optional 值,也不能置為 nil 。如果嘗試調(diào)用這個(gè)無效引用,就會導(dǎo)致崩潰

weak 相對來說友好一些。在它引用的內(nèi)容被釋放后,會置為 nil。(因此,標(biāo)為weak的值都是 Optional 值)

weak 和 unowned 的使用選擇。Apple的建議是,如果確定一個(gè)訪問時(shí)候不會已經(jīng)被釋放,用 unowned 。不確定會不會被釋放,用 weak。

  • delegate 防止循環(huán)引用

     @objc protocol ProtocolB {
        func protocolAction()
    }
    
    //  用weak修飾
    weak var delegate : ProtocolB!;
    
  • 閉包防止循環(huán)引用

lazy var blockAction: () -> () = {
    [weak self] in
    if let strongSelf = self {
        print("\(String(describing: self))")
    }
}

--

@autoreleasepool

Swift 的內(nèi)存管理還是使用的ARC。不用顯式的調(diào)用 retain release autorelease 這些方法,但方法還是會被調(diào)用,只不過在編譯器在合適的地方幫我們加入了。

retain release很直接,就是將對象的引用計(jì)數(shù) +1 或者 -1
autorelease 將接收到該消息的對象放到一個(gè)預(yù)先建立的自動釋放池中,并在自動釋放池收到drain消息時(shí)將這些對象的引用計(jì)數(shù) -1 ,然后將它們從釋放池中移除。

app中,主線程就是跑在一個(gè)自動釋放池中,并且在每個(gè)主runloop結(jié)束時(shí)進(jìn)行drain操作。這是一種必要的延遲釋放方式,因?yàn)槲覀冇袝r(shí)候需要確保在?法內(nèi)部初始化的?成的對象在被返回后別?還能使?,?不是?即被釋放掉。

有一種情況,我們需要自動釋放:就是面對在一個(gè)方法作用域中要生成大量的autorelease對象的時(shí)候。

--

值類型和引?類型

swfit的類型分為值類型和引用類型兩種。值類型在傳遞和賦值時(shí)將進(jìn)行復(fù)制,引用類型只使用引用對象的一個(gè)“指向”。

值類型 引用類型
struct enum 所有內(nèi)建類型包括Int Bool String Array Dictionary 自定義的 class 類型

使用值類型,相較于傳統(tǒng)的引用類型,減少了堆上內(nèi)存分配和回收的次數(shù)。

swift的值類型,復(fù)制的操作只發(fā)生在有必要的時(shí)候。簡單的賦值、參數(shù)的傳遞等,可能名字不同,實(shí)際上都是訪問的同一個(gè)內(nèi)存空間。

值類型復(fù)制的時(shí)機(jī)發(fā)生在值類型的內(nèi)容發(fā)上改變時(shí)。

值類型復(fù)制的時(shí)候,會將存儲于其中的值類型一塊復(fù)制,而對其中的引用類型,只復(fù)制一份引用。

Tip:
在需要處理大量數(shù)據(jù)并且頻繁操作(增減)其中元素時(shí),選擇 NSMutableArray 和 NSMutabelDictionary 會更好
對于容器內(nèi)條目小而容器本身數(shù)目多的情況,使用swift內(nèi)建的Array和Dictionary

--

String 還是 NSString

盡可能使用String

原因:

  1. String和NSString雖然可以方便的互相轉(zhuǎn)化,但是沒必要麻煩自己。
  2. swift中String是struct,相比OC中的NSString class,更切合字符串'不變'的特性。
  3. 有些語法 String 可以用而 NSString不能用。 比方說 for...in 便利字符串中每個(gè)字符

使用range時(shí)候,將String轉(zhuǎn)為NSString更方便些。

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

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

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