Swift 元類型、self称鳞、Self涮较、AnyObject、Any和AnyClass

1.元類型

元類型是指所有類型的類型冈止,包括類狂票、結(jié)構(gòu)體、枚舉和協(xié)議熙暴。
類闺属、結(jié)構(gòu)體或枚舉類型的元類型是相應(yīng)的類型名緊跟.Type慌盯。
協(xié)議類型的元類型——并不是運行時適配該協(xié)議的具體類型——是該協(xié)議名字緊跟.Protocol。
比如掂器,類SomeClass的元類型就是SomeClass.Type亚皂,協(xié)議SomeProtocol的元類型就是SomeProtocal.Protocol。
你可以使用后綴self表達式來獲取類型国瓮。比如孕讳,SomeClass.self返回SomeClass本身,而不是SomeClass的一個實例巍膘。同樣厂财,SomeProtocol.self返回SomeProtocol本身,而不是運行時適配SomeProtocol的某個類型的實例峡懈。還可以對類型的實例使用type(of: someInstance)表達式來獲取該實例在運行階段的類型

protocol TestProtocol {
    func test()
}
class SomeBaseClass {
        class func printClassName() {
            print("SomeBaseClass")
        }
}
class SomeSubClass: SomeBaseClass {
        var title = "標(biāo)題"
        override class func printClassName() {
            print("SomeSubClass")
        }
}
let someInstance: SomeBaseClass = SomeSubClass()
print(type(of: someInstance))
print(type(of: SomeSubClass.self))
print(type(of: TestProtocol.self))


SomeSubClass
SomeSubClass.Type
TestProtocol.Protocol
2. .self和self

T.self:T是實例對象璃饱,當(dāng)前T.self返回的就是實例對象本身;T是類肪康,當(dāng)前T.self返回的就是類型本身

let p = SomeSubClass()
print("\(p.self) === \(type(of: p.self))")
print("\(SomeSubClass.self)--------\(type(of: SomeSubClass.self))")


TestDemo1.ViewController.SomeSubClass === SomeSubClass
SomeSubClass--------SomeSubClass.Type

在實例方法中self是實例對象的本身荚恶;在類方法中self是類型本身。

class SomeSubClass: SomeBaseClass {
        var title = "標(biāo)題"
        class func test(){
            print("類方法:\(self)")
        }
        func test(){
            print("對象方法:\(self)")
        }
        
    }



對象方法:TestDemo1.ViewController.SomeSubClass
類方法:SomeSubClass
3.Self

Self類型不是特定類型磷支,而是為了方便引用當(dāng)前類型谒撼,而無需重復(fù)或知道該類型的名稱。在協(xié)議聲明或者協(xié)議成員聲明中雾狈,Self類型是指最終符合協(xié)議的類型廓潜。

func get() -> Self {
      return self
}
static let age = 18
func test1(){
   print("Self指代類型本身:\(Self.age)")
}

4.AnyObject、Any和AnyClass

AnyObject可以代表任意 class 類型(用來替代OC中的 id)

public typealias AnyObject

由定義就可以看出它就是一個接口善榛,所有的 class 都隱式地實現(xiàn)了這個接口辩蛋。所以 AnyObject 只適用于 class 類型。但是 swift 中的基本類型都是 struct 類型移盆,并不能用 AnyObject 來表示悼院。所以官方又提出了一個更特殊的 Any 類型,它除了 class 以外還可以表示其他類型咒循,可以說是任意類型(包括 struct据途,enum,func等)叙甸。
例如:

let swiftArr = ["a", "b", "c"]
let swiftStr = "hello world"
var array = [AnyObject]()
array.append(swiftArr as AnyObject)
array.append(swiftStr as AnyObject)

這里我們顯示的將 swift 中的 String 和 Array 轉(zhuǎn)成了 AnyObject颖医。實際上 array 里面的元素已經(jīng)變成了 NSString 和 NSArray 了。



當(dāng)然我們還有另外的方式解決此問題蚁署,用 Any便脊。

let swiftArr1 = ["a", "b", "c"]
let swiftStr1 = "hello world"
var array1 = [Any]()
array1.append(swiftArr1)
array1.append(swiftStr1)

可以看到結(jié)果全部是 swift 中的原生類型



值得注意的是 Any 類型使用的時候需要使用 as 關(guān)鍵字做類型轉(zhuǎn)換, 例如:

let string = mixed.first as? String {
print("The first element of mixed is \(string)")
}

AnyClass是AnyObject.Type的別名而已

public typealias AnyClass = AnyObject.Type

表示任意類的元類型蚂四,任意類的類型都隱式遵守這個協(xié)議光戈,一般我們使用不多

5.可選類型(Optional)

您可以通過追加將數(shù)據(jù)類型簡單地表示為 Optional哪痰。 方法是類型附加! 或 ?。 如果可選變量中包含一個值久妆,則將其值返回為 Optional <Value>晌杰,否則返回nil。

var someValue:Int?
var someAnotherValue:Int!
print(someValue)
print(someAnotherValue)

注意:訪問null的未包裝可選對象時發(fā)生致命錯誤崩潰

var someValue:Int!
var unwrappedValue:Int = someValue 

當(dāng)您運行該程序時筷弦,您將得到致命錯誤的崩潰:解開Optional值時意外發(fā)現(xiàn)nil肋演,因為代碼unwrappedValue:Int = someValue試圖將Optional someValue中的值分配給變量unwrappedValue。
但是烂琴,somevalue 是一個包含 nil 值的可選類型爹殊。試圖將 nil 值分配給變量 unwrappedValue (這不是一個Optional)將導(dǎo)致崩潰。
可以用if判斷nil+iflet+guard三種方式處理上面崩潰問題

6.類型別名(Typealias)

類型別名不會創(chuàng)建新類型奸绷。它們只是為現(xiàn)有類型提供一個新名稱梗夸。

typealias name = existing type

在Swift中,大多數(shù)類型都可以使用typealias号醉。它們可以是:
1.內(nèi)置類型(例如:String, Int)
2.用戶定義的類型(例如:類反症,結(jié)構(gòu),枚舉)
3.復(fù)雜類型(例如:閉包)

func someMethod(oncomp:(Int)->(String)){

}
typealias CompletionHandler = (Int)->(String)
func someMethod(oncomp:CompletionHandler){

}
7.關(guān)聯(lián)類(associatedtype)

associatedtype定義關(guān)聯(lián)類型畔派,相當(dāng)于類型的占位符铅碍,讓實現(xiàn)協(xié)議的類型來指定具體的類型

protocol Food {
    
}

protocol Animal {
    associatedtype F: Food
    func eat(_ food: F)
}

struct Meat: Food {
    
}

struct Tiger: Animal {
    func eat(_ food: Meat) {
        print("eat \(food)")
    }
}


/*

具有關(guān)聯(lián)類型的協(xié)議類型,只能當(dāng)做泛型約束使用
 
錯誤代碼:
func isTiger(animal: Animal) -> Bool {

}
*/

// 具有關(guān)聯(lián)類型的協(xié)議類型线椰,只能當(dāng)做泛型約束使用
func isTiger<A: Animal>(animal: A) -> Bool {
    if animal is Tiger {
        return true
    } else {
        return false
    }
}

8.類型修飾詞

1.available

可用來標(biāo)識計算屬性胞谈、函數(shù)、類憨愉、協(xié)議呜魄、結(jié)構(gòu)體、枚舉等類型的生命周期莱衩。(依賴于特定的平臺版本 或 Swift 版本)爵嗅。它的后面一般跟至少兩個參數(shù),參數(shù)之間以逗號隔開笨蚁。

if #available(iOS 11.0, *) {

  scrollView.contentInsetAdjustmentBehavior = .never

} else {

  automaticallyAdjustsScrollViewInsets = false

}
還有一種用法是放在函數(shù)睹晒、結(jié)構(gòu)體、枚舉括细、類或者協(xié)議的前面伪很,表示當(dāng)前類型僅適用于某一平臺
@available(iOS 12.0, *)
func adjustDarkMode() {
  /* code */
}
@available(iOS 12.0, *)
struct DarkModeConfig {
  /* code */
}
@available(iOS 12.0, *)
protocol DarkModeTheme {
  /* code */
}

2.@discardableResult

帶返回的函數(shù)如果沒有處理返回值會被編譯器警告。但有時我們就是不需要返回值的奋单,這個時候我們可以讓編譯器忽略警告锉试,就是在方法名前用@discardableResult聲明一下±辣簦可以參考Alamofire中request的寫法:

@discardableResult
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest
{
    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )
}

3.@inlinable

這個關(guān)鍵詞是可內(nèi)聯(lián)的聲明呆盖,它來源于C語言中的inline拖云。C中一般用于函數(shù)前,做內(nèi)聯(lián)函數(shù)应又,它的目的是防止當(dāng)某一函數(shù)多次調(diào)用造成函數(shù)棧溢出的情況宙项。因為聲明為內(nèi)聯(lián)函數(shù),會在編譯時將該段函數(shù)調(diào)用用具體實現(xiàn)代替株扛,這么做可以省去函數(shù)調(diào)用的時間尤筐。
內(nèi)聯(lián)函數(shù)常出現(xiàn)在系統(tǒng)庫中,OC中的runtim中就有大量的inline使用
需要注意內(nèi)聯(lián)聲明不能用于標(biāo)記為private或者fileprivate的地方,這很好理解洞就,對私有方法的內(nèi)聯(lián)是沒有意義的盆繁。內(nèi)聯(lián)的好處是運行時更快。因為是編譯時做替換旬蟋,這增加了編譯的開銷改基,會相應(yīng)的延長編譯時間。

4.@warn_unqualified_access

通過命名我們可以推斷出其大概含義:對“不合規(guī)”的訪問進行警告咖为。這是為了解決對于相同名稱的函數(shù)秕狰,不同訪問對象可能產(chǎn)生歧義的問題。
比如說躁染,Swift 標(biāo)準(zhǔn)庫中Array和Sequence均實現(xiàn)了min()方法鸣哀,而系統(tǒng)庫中也定義了min(::),對于可能存在的二義性問題吞彤,我們可以借助于@warn_unqualified_access我衬。

extension Array where Self.Element : Comparable {
  @warn_unqualified_access
  @inlinable public func min() -> Element?
}
extension Sequence where Self.Element : Comparable {
  @warn_unqualified_access
  @inlinable public func min() -> Self.Element?
}
extension Array where Element: Comparable {
    func minValue() -> Element? {
        return min()
    }
}

我們會收到編譯器的警告:Use of 'min' treated as a reference to instance method in protocol 'Sequence', Use 'self.' to silence this warning。它告訴我們編譯器推斷我們當(dāng)前使用的是Sequence中的min()饰恕,這與我們的想法是違背的挠羔。因為有這個@warn_unqualified_access限定,我們能及時的發(fā)現(xiàn)問題埋嵌,并解決問題:self.min()破加。

5.@objc

把這個特性用到任何可以在 Objective-C 中表示的聲明上——例如,非內(nèi)嵌類雹嗦,協(xié)議范舀,非泛型枚舉(原始值類型只能是整數(shù)),類和協(xié)議的屬性了罪、方法(包括 setter 和 getter )锭环,初始化器,反初始化器泊藕,下標(biāo)辅辩。 objc 特性告訴編譯器,這個聲明在 Objective-C 代碼中是可用的。
@objc還有一個用處是當(dāng)你想在OC的代碼中暴露一個不同的名字時玫锋,可以用這個特性蛾茉,它可以用于類,函數(shù)景醇,枚舉,枚舉成員吝岭,協(xié)議三痰,getter,setter等窜管。

當(dāng)在OC代碼中訪問enabled的getter方法時散劫,是通過isEnabled
class ExampleClass: NSObject {

    @objc var enabled: Bool {

        @objc(isEnabled) get {

            // Return the appropriate value

        }

    }

}

6.@objcMembers

因為Swift中定義的方法默認(rèn)是不能被OC調(diào)用的,除非我們手動添加@objc標(biāo)識幕帆。但如果一個類的方法屬性較多获搏,這樣會很麻煩,于是有了這樣一個標(biāo)識符@objcMembers失乾,它可以讓整個類的屬性方法都隱式添加@objc常熙,不光如此對于類的子類、擴展碱茁、子類的擴展都也隱式的添加@objc裸卫,當(dāng)然對于OC不支持的類型,仍然無法被OC調(diào)用

7.@frozen 和@unknown default

@frozen即凍結(jié)纽竣,保證之后該值類型不會再變墓贿。其實我們常用的類型像Int、Float蜓氨、Array聋袋、Dictionary、Set等都已被“凍結(jié)”穴吹。需要說明的是凍結(jié)僅針對struct和enum這種值類型幽勒,因為他們在編譯器就確定好了內(nèi)存布局。
對于沒有標(biāo)記為frozen的枚舉例如AVPlayerItem.Status港令,則認(rèn)為該枚舉值在之后的系統(tǒng)版本中可能變化代嗤。對于可能變化的枚舉,我們在列出所有case的時候還需要加上對@unknown default的判斷缠借,這一步會有編譯器檢查干毅。

switch currentItem.status {

    case .readyToPlay:

        /* code */

    case .failed:

        /* code */

    case .unknown:

        /* code */

    @unknown default:

        fatalError("not supported")

}
  1. lazy

lazy是懶加載的關(guān)鍵詞,當(dāng)我們僅需要在使用時進行初始化操作就可以選用該關(guān)鍵詞泼返。

lazy var dayLabel: UILabel = {

    let label = UILabel()

   label.text = self.todayText()

    return label

}()

使用lazy你可能會發(fā)現(xiàn)它只能通過var初始而不能通過let硝逢,這是由lazy 的具體實現(xiàn)細(xì)節(jié)決定的:它在沒有值的情況下以某種方式被初始化,然后在被訪問時改變自己的值,這就要求該屬性是可變的渠鸽。

9.unowned weak

weak相當(dāng)于oc里面的weak叫乌,弱引用,不會增加循環(huán)計數(shù)徽缚。主體對象釋放時被weak修飾的屬性也會被釋放憨奸,所以weak修飾對象就是optional。

·unowned相當(dāng)于oc里面的unsafe_unretained凿试,它不會增加引用計數(shù)排宰,即使它的引用對象釋放了,它仍然會保持對被已經(jīng)釋放了的對象的一個 "無效的" 引用那婉,它不能是 Optional 值板甘,也不會被指向nil。如果此時為無效引用详炬,再去嘗試訪問它就會crash盐类。

lazy var someClosure: () -> Void = { [weak self] in
    // 被weak修飾后self為optional,這里是判斷self非空的操作                                
    guard let self = self else { retrun }
    self.doSomethings()
}

10.some

some是Swift5.1新增的特性呛谜。它的用法就是修飾在一個 protocol 前面在跳,默認(rèn)場景下 protocol 是沒有具體類型信息的,但是用some 修飾后隐岛,編譯器會讓 protocol 的實例類型對外透明硬毕。

可以通過一個例子理解這段話的含義,當(dāng)我們嘗試定義一個遵循Equatable協(xié)議的value時:

// Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements
var value: Equatable {
    return 1
}

var value: Int {
    return 1
}

編譯器提示我們Equatable只能被用來做泛型的約束礼仗,它不是一個具體的類型吐咳,這里我們需要使用一個遵循Equatable的具體類型(Int)進行定義。但有時我們并不想指定具體的類型元践,這時就可以在協(xié)議名前加上some韭脊,讓編譯器自己去推斷value的類型:

var value: some Equatable {
    return 1
}
struct ContentView: View {
    var body: some View {
        Text("Hello World")
    }
}
9.屬性修飾詞和權(quán)限控制詞

swift提供了5個不同的訪問級別,權(quán)限最高的是open单旁,其次依次是public沪羔、internal、fileprivate象浑,最低是private蔫饰。默認(rèn)使用的是internal。
open & public
使用open和public定義的實體愉豺,在它們定義的module的任意文件中皆可使用篓吁。其他module如果import了此實體,則其他module的源文件也可使用蚪拦。一般在framework中指定的公開接口里杖剪,使用open和public級別冻押。
open 和 public 的區(qū)別
public或更低權(quán)限的類,只能在其定義的module中子類化
public或更低權(quán)限的類的成員盛嘿,只能在其定義的module中被重寫或子類化
open權(quán)限的類洛巢,可在其定義的module,或者import了其的module中子類化
open權(quán)限的類的成員次兆,可在其定義的module稿茉,或者import了其的module中重寫或子類化
internal
intenal修飾的實體在其定義的module中皆可使用,但是在其他module中無法使用芥炭。一般定義APP或者framework內(nèi)部結(jié)構(gòu)的時候漓库,會使用internal級別
fileprivate
fileprivate定義的實體,只能在其源文件中使用蚤认,當(dāng)其只在整個源文件中使用的時候米苹,使用fileprivate級別
private
private定義的實體糕伐,只能在定義的范圍內(nèi)砰琢,和其在同一文件的extension中使用,當(dāng)其只在當(dāng)前聲明范圍內(nèi)使用的時候良瞧,使用private級別

使用原則
子類:子類的訪問級別不可以高于父類陪汽,但子類重寫的方法的訪問級別可以高于父類
枚舉:枚舉的每個值都和它們所屬枚舉有相同的權(quán)限,且不能單獨為某個值定義權(quán)限
協(xié)議:協(xié)議可以指定訪問級別褥蚯,并且對于協(xié)議的每一項來說挚冤,都和協(xié)議的訪問級別相同,不能單獨為協(xié)議的某個方法指定不同的訪問級別

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赞庶,一起剝皮案震驚了整個濱河市训挡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歧强,老刑警劉巖澜薄,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摊册,居然都是意外死亡肤京,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門茅特,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忘分,“玉大人,你說我怎么就攤上這事白修《事停” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵兵睛,是天一觀的道長舟山。 經(jīng)常有香客問我绸狐,道長,這世上最難降的妖魔是什么累盗? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任寒矿,我火速辦了婚禮,結(jié)果婚禮上若债,老公的妹妹穿的比我還像新娘符相。我一直安慰自己,他們只是感情好蠢琳,可當(dāng)我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布啊终。 她就那樣靜靜地躺著,像睡著了一般傲须。 火紅的嫁衣襯著肌膚如雪蓝牲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天泰讽,我揣著相機與錄音例衍,去河邊找鬼。 笑死已卸,一個胖子當(dāng)著我的面吹牛佛玄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播累澡,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼梦抢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了愧哟?” 一聲冷哼從身側(cè)響起奥吩,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蕊梧,沒想到半個月后霞赫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡望几,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年绩脆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橄抹。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡靴迫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楼誓,到底是詐尸還是另有隱情玉锌,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布疟羹,位于F島的核電站主守,受9級特大地震影響禀倔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜参淫,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一救湖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涎才,春花似錦鞋既、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棕兼,卻和暖如春陡舅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伴挚。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工靶衍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人章鲤。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓摊灭,卻偏偏與公主長得像咆贬,于是被迫代替她去往敵國和親败徊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容