六、類與結(jié)構(gòu)體
結(jié)構(gòu)體
swift中結(jié)構(gòu)體和類十分相似,即可定義屬性,又可以定義方法,但不具有繼承的特性。使用struct定義結(jié)構(gòu)體,結(jié)構(gòu)體中聲明變量或者常量作為結(jié)構(gòu)體屬性,可以創(chuàng)建函數(shù)作為結(jié)構(gòu)體的方法,用點(diǎn)語法調(diào)用屬性和方法。
struct Car {
? ? //價(jià)格
? ? var price:NSInteger
? ? //品牌
? ? var brand:String
? ? //油量
? ? var petrol:NSInteger
? ? //提供一個(gè)駕駛方法
? ? mutating func drive(){
? ? ? ? if petrol > 0{
? ? ? ? ? ? petrol -= 1
? ? ? ? ? ? print(petrol)
? ? ? ? }
? ? }
? ? //提供一個(gè)加油方法
? ? mutating func addPetrol(){
? ? ? ? petrol += 10
? ? ? ? print("加了10升油")
? ? }
}
func testStructAndClass(){
? ? var car = Car(price: 300000, brand: "奔馳", petrol: 60)
? ? print("這輛:\(car.brand) 價(jià)格:\(car.price) 油量:\(car.petrol)”)
var car1:Car = car
? ? car1.drive();
? ? print(car.petrol)
? ? print(car1.petrol)
}//打印60 59
類是基本數(shù)據(jù)類型,car1和car是兩塊數(shù)據(jù)。
struct PointStruct {
? ? var x:Double
? ? var y:Double
? ? //結(jié)構(gòu)體中,如果修改值類型的變量需要用mutating關(guān)鍵字修飾
? ? mutating func move(x:Double, y:Double){
? ? ? ? self.x += x
? ? ? ? self.y += y
? ? }
}
2.類
類和結(jié)構(gòu)體在屬性和方法聲明上都一樣,不同的是,結(jié)構(gòu)體中不提供構(gòu)造方法,結(jié)構(gòu)體會(huì)根據(jù)屬性自動(dòng)生成一個(gè)構(gòu)造方法,而類需要開發(fā)者自己提供構(gòu)造方法,在init()構(gòu)造方法中需要完成對(duì)類屬性的賦值操作。
class ClassCar{
? ? //價(jià)格
? ? var price:NSInteger
? ? //品牌
? ? var brand:String
? ? //油量
? ? var petrol:NSInteger
? ? //提供一個(gè)駕駛方法
? ? func drive(){
? ? ? ? if petrol > 0{
? ? ? ? ? ? petrol -= 1
? ? ? ? ? ? print(petrol)
? ? ? ? }
? ? }
? ? //提供一個(gè)加油方法
? ? func addPetrol(){
? ? ? ? petrol += 10
? ? ? ? print("加了10升油")
? ? }
? ? //類比結(jié)構(gòu)體多了個(gè)構(gòu)造方法
? ? init(price:NSInteger, brand:String, petrol:NSInteger) {
? ? ? ? self.price = price
? ? ? ? self.brand = brand
? ? ? ? self.petrol = petrol
? ? }
}
類是引用類型,對(duì)類實(shí)例進(jìn)行數(shù)據(jù)傳遞時(shí)不會(huì)產(chǎn)生復(fù)制行為。
? ? var car3:ClassCar = ClassCar.init(price: 300000, brand: "寶馬", petrol: 55)
? ? var car4:ClassCar = car3
? ? car3.drive();
? ? print(car3.petrol)
? ? print(car4.petrol)
? ? //打印54 car3 car4指向同一個(gè)對(duì)象
3.類的繼承
子類繼承父類如果要重寫父類的方法,用關(guān)鍵字override,可以調(diào)用父類的此方法。
class BMWCar: ClassCar {
? ? override func drive() {
? ? ? ? super.drive()
? ? ? ? petrol -= 1
? ? }
? ? override init(price:NSInteger, brand:String="寶馬", petrol:NSInteger) {
? ? ? ? super.init(price: price, brand: brand, petrol: petrol)
? ? }
}
關(guān)鍵字final修飾不可被重寫的屬性或者方法。
? ? final func addPetrol(){
? ? ? ? petrol += 10
? ? ? ? print("加了10升油")
? ? }
4.容器的實(shí)現(xiàn)
swift中Array,String,Dictionary,Set都是采用結(jié)構(gòu)體實(shí)現(xiàn)的,這點(diǎn)和oc有很大區(qū)別,因此上述實(shí)例在數(shù)據(jù)傳遞時(shí)會(huì)發(fā)生復(fù)制,深拷貝。
? ? var arr1:Array = [0,1,2]
? ? var arr2:Array = arr1
? ? arr1.append(3)
? ? print(arr1)
? ? print(arr2)
? ? //打印
[0, 1, 2, 3]
? ? [0, 1, 2]
5.屬性初值
可以在屬性聲明時(shí)提供一個(gè)初值
class BMWCar: ClassCar {
? ? var color: String = "藍(lán)色"
}
6.延時(shí)存儲(chǔ)屬性(懶加載屬性)
延時(shí)存儲(chǔ)屬性用lazy修飾,類構(gòu)造時(shí)候,延時(shí)存儲(chǔ)屬性并不進(jìn)行構(gòu)造初始化,只有當(dāng)開發(fā)者調(diào)用到類實(shí)例的這個(gè)屬性時(shí),此屬性才完成構(gòu)造或者初始化,延時(shí)存儲(chǔ)屬性可以減少類實(shí)例的構(gòu)造時(shí)間。
class Wheel{
? ? var name:String
? ? var bar:Float
? ? init(name:String, bar:Float) {
? ? ? ? self.name = name
? ? ? ? self.bar = bar
? ? }
}
class ClassCar{
? ? lazy var wheel:Wheel = Wheel(name: "左前輪", bar: 2.5)
}
延時(shí)構(gòu)造屬性不是線程安全的,如果在多個(gè)線程中對(duì)延時(shí)存儲(chǔ)屬性進(jìn)行調(diào)用,不能保證只被構(gòu)造一次。
7.get、set方法
class RectClass {
? ? var width:Float
? ? var height:Float
? ? var area:Float{
? ? ? ? get{//定義面積長(zhǎng)x寬
? ? ? ? ? ? return width*height
? ? ? ? }
? ? ? ? set{//計(jì)算寬度=面積/高? newValue是set方法固定值
? ? ? ? ? ? width = newValue/height
? ? ? ? }
? ? }
? ? init(width:Float, height:Float) {
? ? ? ? self.width = width
? ? ? ? self.height = height
? ? }
}
? ? var rect:RectClass = RectClass.init(width: 5, height: 10)
? ? print(rect.width, rect.height, rect.area)
? ? rect.area = 100
? ? print(rect.width, rect.height, rect.area)
? ? //輸出5.0 10.0 50.0
? ? //10.0 10.0 100.0
8.屬性監(jiān)聽器
進(jìn)行屬性初始化時(shí),無論通過構(gòu)造方法設(shè)置屬性或者通過屬性設(shè)置默認(rèn)值都不會(huì)調(diào)用屬性監(jiān)聽器的方法,初始化之后第二次為屬性賦值開始,屬性監(jiān)聽器才會(huì)被調(diào)用。
class RectClass {
? ? var width:Float{
? ? ? ? willSet{
? ? ? ? ? ? print("將要設(shè)置的值:\(newValue)")
? ? ? ? }
? ? ? ? didSet{
? ? ? ? ? ? print("舊的值:\(oldValue)")
? ? ? ? }
? ? }
? ? var height:Float
? ? var area:Float{
? ? ? ? get{//定義面積長(zhǎng)x寬
? ? ? ? ? ? return width*height
? ? ? ? }
? ? ? ? set{//計(jì)算寬度=面積/高? newValue是set方法固定值
? ? ? ? ? ? width = newValue/height
? ? ? ? }
? ? }
? ? init(width:Float, height:Float) {
? ? ? ? self.width = width
? ? ? ? self.height = height
? ? }
}
? ? //初始化時(shí)候width是5
? ? var rect:RectClass = RectClass.init(width: 5, height: 10)
? ? print(rect.width, rect.height, rect.area)
? ? //間接調(diào)用了width的set,新值為10
? ? rect.area = 100
? ? print(rect.width, rect.height, rect.area)
? ? //輸出將要設(shè)置的值:10.0
? ? //舊的值:5.0
? ? //10.0 10.0 100.0
只有存儲(chǔ)屬性可以設(shè)置屬性監(jiān)聽器(width、height),而計(jì)算屬性不能設(shè)置屬性監(jiān)聽。
9.類屬性與類方法
類屬性由static或者class關(guān)鍵字聲明,如果希望子類可以對(duì)計(jì)算方法可以重寫,需要用class關(guān)鍵字聲明。
static定義的類方法也不能被子類重寫,class定義的類方法可以被子類重寫。
class SomeClass{
? ? static var className:String = "class name"
? ? class var subName:String{
? ? ? ? return "sub"+className
? ? }
}
10.下標(biāo)方法
下標(biāo)使用subscript關(guān)鍵字定義,參數(shù)和返回值分別作為下標(biāo)和通過下標(biāo)所取的值,subscript的實(shí)現(xiàn)與計(jì)算屬性類似,必須實(shí)現(xiàn)一個(gè)get,可選實(shí)現(xiàn)set,get用于取值,set用于賦值。
下標(biāo)訪問不局限于一維下標(biāo),可以實(shí)現(xiàn)任意維度的下標(biāo)訪問功能。
class MyArray{
? ? var array:Array<Array<NSInteger>>
? ? init(param:Array<NSInteger>...) {
? ? ? ? array = param
? ? }
? ? subscript(index1:NSInteger, index2:NSInteger)->NSInteger{
? ? ? ? set{
? ? ? ? ? ? array[index1][index2] = newValue
? ? ? ? }
? ? ? ? get{
? ? ? ? ? ? let temp = array[index1]
? ? ? ? ? ? return temp[index2]
? ? ? ? }
? ? }
}
? ? var array = MyArray(param: [1,2,3],[4,5,6],[7,8,9])
? ? print(array[1, 1])
? ? array[1, 1] = 12
? ? print(array[1,1])
? ? //打印5
? ? //12
11.結(jié)構(gòu)體和類在構(gòu)造方法結(jié)束前完成其中存儲(chǔ)屬性的構(gòu)造(延時(shí)存儲(chǔ)屬性除外)。
兩種初始化方法
1.存儲(chǔ)屬性聲明時(shí)直接為其設(shè)置初始默認(rèn)值
2.在構(gòu)造方法里對(duì)存儲(chǔ)屬性構(gòu)造設(shè)默認(rèn)值
如果某個(gè)屬性邏輯上允許為nil,開發(fā)者可以將其聲明為optional可選值類型,對(duì)于optional類型的屬性,如果在構(gòu)造方法中不進(jìn)行賦值,就會(huì)被默認(rèn)賦值為nil。
class Wheel{
? ? var name:String?//如果不進(jìn)行可選值類型的聲明就必須初始化時(shí)候設(shè)默認(rèn)值或者init里面構(gòu)造,否則編譯出錯(cuò)。
? ? var bar:Float
? ? init(name:String, bar:Float) {
//? ? ? ? self.name = name
? ? ? ? self.bar = bar
? ? }
}
如果類或者結(jié)構(gòu)體所有的存儲(chǔ)屬性都有初始默認(rèn)值,開發(fā)者不顯示的提供任何構(gòu)造方法,編譯期也會(huì)默認(rèn)生成一個(gè)無參的構(gòu)造方法init(),在進(jìn)行類型的實(shí)例化時(shí),構(gòu)造出來的實(shí)例所有屬性值都是默認(rèn)的初始值。
class Wheel{
? ? var name:String = "左前輪"
? ? var bar:Float = 2.5
}
11. 指定構(gòu)造方法和便利構(gòu)造方法
構(gòu)造方法分為指定構(gòu)造方法和便利構(gòu)造方法
指定構(gòu)造方法名稱為designated,是基礎(chǔ)構(gòu)造方法,任何類至少有一個(gè)指定構(gòu)造方法。
便利構(gòu)造方法使用convenience關(guān)鍵字來修飾,是為了方便開發(fā)者使用,為類額外添加的構(gòu)造方法。便利構(gòu)造方法最終也要調(diào)用到指定構(gòu)造方法。
原則:
1.子類的指定構(gòu)造方法必須調(diào)用父類的指定構(gòu)造方法
2.便利構(gòu)造方法中必須調(diào)用當(dāng)前類的其它構(gòu)造方法
3.便利構(gòu)造方法最終要調(diào)用到某個(gè)指定構(gòu)造方法
class BaseClass{
? ? init() {指定構(gòu)造方法
? ? ? ? print("指定構(gòu)造方法")
? ? }
? ? convenience init(param:String) {//便利構(gòu)造方法
? ? ? ? print("便利構(gòu)造方法")
? ? ? ? self.init()
? ? }
}
class subClass: BaseClass {
? ? override init() {//指定構(gòu)造方法
? ? ? ? super.init()
? ? }
? ? convenience init(param:String) {//便利構(gòu)造方法
? ? ? ? self.init()
? ? }
? ? convenience init(param:Int) {//便利構(gòu)造方法
? ? ? ? self.init(param:"hhhh")
? ? }
}
12. 構(gòu)造方法的繼承
在繼承關(guān)系中,如果子類沒有重寫任何指定構(gòu)造方法,則默認(rèn)子類會(huì)繼承父類的所有指定構(gòu)造方法,如果子類定義了自己的指定構(gòu)造方法,或者重寫了父類的某個(gè)指定構(gòu)造方法,則子類不再繼承父類的所有指定構(gòu)造方法。
如果子類提供了父類所有的指定構(gòu)造方法(無論是繼承還是重寫),則子類會(huì)默認(rèn)繼承父類的便利構(gòu)造方法。
class BaseClass{
? ? init() {//指定構(gòu)造方法
? ? ? ? print("指定構(gòu)造方法")
? ? }
? ? init(param:Int) {
? ? ? ? print("指定構(gòu)造方法param")
? ? }
? ? convenience init(param:String) {//便利構(gòu)造方法
? ? ? ? print("便利構(gòu)造方法")
? ? ? ? self.init()
? ? }
}
//此類中不進(jìn)行任何構(gòu)造方法的定義,默認(rèn)繼承父類的所有構(gòu)造方法
class subClass1: BaseClass {
}
//對(duì)無參的init指定構(gòu)造方法進(jìn)行重寫,則不再繼承父類的其他構(gòu)造方法
class subClass2: BaseClass {
? ? override init() {
? ? ? ? super.init()
? ? }
}
//沒有重寫父類的構(gòu)造方法,但是重載定義了自己的構(gòu)造方法,則不再繼承父類的其他構(gòu)造方法
class subClass3: BaseClass {
? ? init(param:Bool) {
? ? ? ? super.init()
? ? }
}
//此類中不進(jìn)行任何構(gòu)造方法的定義,默認(rèn)繼承父類的所有構(gòu)造方法
class subClass4: BaseClass {
? ? override init() {
? ? ? ? super.init()
? ? }
? ? override init(param: Int) {
? ? ? ? super.init(param: param)
? ? }
}
13. 構(gòu)造方法的安全性檢查
1.子類的指定構(gòu)造方法中,必須完成當(dāng)前類所有的存儲(chǔ)屬性的構(gòu)造,才能調(diào)用父類的指定構(gòu)造方法,此檢查可以保證:在構(gòu)造完從父類繼承下來的所有存儲(chǔ)屬性前,本身定義的所有屬性也已經(jīng)構(gòu)造完成。
2.子類如果要定義父類中存儲(chǔ)屬性的值,必須在調(diào)用父類構(gòu)造方法之后進(jìn)行設(shè)置,此檢查可以保證:子類在設(shè)置從父類繼承下來的存儲(chǔ)屬性時(shí),此屬性已經(jīng)完成構(gòu)造。
3.如果便利構(gòu)造方法中需要重新設(shè)置某些存儲(chǔ)屬性的值,必須在調(diào)用指定構(gòu)造方法之后進(jìn)行設(shè)置,此檢查可以保證:便利構(gòu)造方法中對(duì)存儲(chǔ)屬性值的設(shè)置不會(huì)被指定的構(gòu)造方法中的設(shè)置覆蓋。
4.子類在調(diào)用父類的構(gòu)造方法之前,不能使用self來引用屬性,此檢查可以保證:使用self調(diào)用實(shí)例本身時(shí),實(shí)例已經(jīng)構(gòu)造完成。
class BaseClassA{
? ? var property:Int
? ? init(param:Int) {
? ? ? ? self.property = param
? ? }
}
class SubClassA: BaseClassA {
? ? var subProperty:Int
? ? init() {
? ? ? ? //檢查原則1:必須在調(diào)用父類構(gòu)造方法前完成本身屬性的賦值
? ? ? ? subProperty = 1
? ? ? ? super.init(param: 0)
? ? ? ? //檢查原則2:如果要重新賦值父類繼承來的某個(gè)屬性,必須在調(diào)用父類的指定構(gòu)造方法后
? ? ? ? property = 2
? ? ? ? //檢查原則4:在完成父類的構(gòu)造方法之后,才能用self關(guān)鍵字
? ? }
? ? convenience init(param1:Int, param2:Int) {
? ? ? ? self.init()
? ? ? ? //檢查原則3:遍歷構(gòu)造方法重要修改屬性的值,必須在調(diào)用指定的構(gòu)造方法之后
? ? ? ? subProperty = param1
? ? ? ? property = param2
? ? }
}
14. 可失敗的構(gòu)造方法與析構(gòu)方法
swift對(duì)于處理某些可能為空的值引入了可選值類型,對(duì)于類的構(gòu)造方法,實(shí)際開發(fā)中可能遇到構(gòu)造失敗的情況,例如需要一些特定的參數(shù),但是參數(shù)不符合要求,構(gòu)造失敗時(shí)返回nil??墒〉臉?gòu)造方法用init?()
class BaseClassA{
? ? var property:Int
? ? init(param:Int) {
? ? ? ? self.property = param
? ? }
? ? //可失敗構(gòu)造方法
? ? init?(param: Bool) {
? ? ? ? guard param else {
? ? ? ? ? ? return nil
? ? ? ? }
? ? ? ? property = 1
? ? }
? ? //析構(gòu)方法
? ? deinit {
? ? }
}
七、內(nèi)存管理
弱引用
class ClassOne{
? ? //用weak進(jìn)行弱引用避免循環(huán)引用
? ? weak var two:ClassTwo?
? ? deinit {
? ? ? ? print("ClassOne deinit")
? ? }
}
class ClassTwo{
? ? var one:ClassOne?
? ? init(one:ClassOne?) {
? ? ? ? self.one = one
? ? }
? ? deinit {
? ? ? ? print("ClassTwo deinit")
? ? }
}
func memoryTest(){
? ? var one:ClassOne? = ClassOne.init()
? ? var two:ClassTwo? = ClassTwo.init(one: one)
? ? one?.two = two
? ? one =nil
? ? two =nil
}
2.無主引用
類似oc的assign,swift提供無主引用,用unowned修飾,被引用對(duì)象釋放時(shí)候引用不會(huì)置nil
class ClassThree{
? ? //無主引用
? ? unowned var four:ClassFour?
? ? deinit {
? ? ? ? print("ClassThree deinit")
? ? }
}
class ClassFour{
? ? var three:ClassThree?
? ? init(three:ClassThree?) {
? ? ? ? self.three = three
? ? }
? ? deinit {
? ? ? ? print("ClassFour deinit")
? ? }
}
? ? var three:ClassThree? = ClassThree.init()
? ? var four:ClassFour? = ClassFour.init(three: three)
? ? three?.four = four
? ? four =nil
? ? three?.four//crash Fatal error: Attempted to read an unowned reference but object 0x6000036a9580 was already deallocated2020-04-09 14:09:46.214608+0800 LearnSwift[53426:10252006] Fatal error: Attempted to read an unowned reference but object 0x6000036a9580 was already deallocated
無主引用與拆包結(jié)合可以使兩個(gè)類的相互引用屬性都是非可選值屬性(非optional),這也是無主引用的最佳場(chǎng)景
class ClassThree{
? ? //無主引用
? ? unowned var four:ClassFour?
? ? init(four:ClassFour) {
? ? ? ? self.four = four
? ? }
? ? deinit {
? ? ? ? print("ClassThree deinit")
? ? }
}
class ClassFour{
? ? //使用隱式拆包
? ? var three:ClassThree!
? ? init() {
? ? ? ? /*在創(chuàng)建three屬性的時(shí)候?qū)?dāng)前類實(shí)例本身作為參數(shù)傳入
? ? ? ? ? 有構(gòu)造方法的原則可知在three屬性創(chuàng)建完成之前,不可以用self屬性
?? ? ? ? 對(duì)于隱式解析類的屬性,上述原則可以忽略,其告訴編譯器默認(rèn)此屬性是構(gòu)造完成的
?? ? ? ? */
? ? ? ? three = ClassThree(four: self)
? ? }
? ? deinit {
? ? ? ? print("ClassFour deinit")
? ? }
}? ?
var? obj5:ClassFour? = ClassFour()
?? ? obj5 = nil
3.block中的循環(huán)引用
class ClassSix{
? ? var name:String = "hhhh"
? ? lazy var close:()->Void = {
? ? ? ? print(self.name)
//self和block產(chǎn)生循環(huán)引用
? ? }
? ? deinit {
? ? ? ? print("ClassSix deinit")
? ? }
}
? ? var obj6:ClassSix? = ClassSix()
? ? obj6?.close()
? ? obj6 =nil
//執(zhí)行完obj6不釋放
class ClassSix{
? ? var name:String = "hhhh"
? ? lazy var close:()->Void = {
? ? ? ? //使用捕獲列表對(duì)block中的self進(jìn)行無主引用的轉(zhuǎn)換
? ? ? ? [unowned self]()->Void in
? ? ? ? print(self.name)
? ? }
? ? deinit {
? ? ? ? print("ClassSix deinit")
? ? }
}
? ? var obj6:ClassSix? = ClassSix()
? ? obj6?.close()
? ? obj6 =nil
//執(zhí)行完obj6可以釋放
3.異常的捕獲
enum MyError:Error {
? ? case DseToryError
? ? case NormarlError
? ? case SimpleError
}
func myFunc(param:Bool) throws -> Void {
? ? if param {
? ? ? ? print("success")
? ? }else{
? ? ? ? throw MyError.NormarlError
? ? }
}
? ? //使用do-catch進(jìn)行異常的捕獲與處理
? ? do {
? ? ? ? try myFunc(param: false)
? ? }catch MyError.SimpleError {
? ? ? ? print("SimpleError")
? ? }catch MyError.NormarlError {
? ? ? ? print("NormarlError")
? ? }catch MyError.DseToryError {
? ? ? ? print("DseToryError")
? ? }catch{
? ? ? ? print("other Error")
? ? }
上述結(jié)構(gòu)可以根據(jù)異常類型進(jìn)行分類處理方案,保證代碼健壯性。
swift還有一種方法,可以將異常映射為optional值,如果函數(shù)沒有異常正常返回,如果執(zhí)行出錯(cuò),拋出異常,則會(huì)返回optional的nil值。使用try?來調(diào)用函數(shù)可以將異常映射為optional值。
? ? let temp = try? myFunc(param: false)
? ? if temp == nil {
? ? ? ? print("執(zhí)行失敗")
? ? }else{
? ? ? ? print("執(zhí)行成功")
? ? }
4.延時(shí)執(zhí)行結(jié)構(gòu)
使用延時(shí)執(zhí)行語句可以保證無論函數(shù)因?yàn)楹畏N原因結(jié)束,在結(jié)束前都會(huì)執(zhí)行延時(shí)執(zhí)行結(jié)構(gòu)塊中的代碼。
func temFun() {
? ? defer {
? ? ? ? print("finish")
? ? }
? ? print("handel")
}
? ? temFun()
? ? //打印handel
? ? //finish
七、類型轉(zhuǎn)換、泛型、擴(kuò)展、協(xié)議
類型檢查
判斷某個(gè)實(shí)例是否屬于某個(gè)類型用關(guān)鍵字is,返回一個(gè)bool值。
? ? var str = "hhh"
? ? if str is String {
? ? ? ? print("str是string類型")
? ? }
類型轉(zhuǎn)換
swift類型轉(zhuǎn)換用as關(guān)鍵字
class MyBaseClass{
? ? var name:String?
}
class MySubClassA: MyBaseClass {
? ? var count:Int?
}
class MySubClassB: MyBaseClass {
? ? var isBiger:Bool?
}
? ? let obj1:MyBaseClass = MyBaseClass()
? ? obj1.name = "hhhhh"
? ? let obj2:MySubClassA = MySubClassA()
? ? obj2.count = 3
? ? let obj3:MySubClassB = MySubClassB()
? ? obj3.isBiger = true
? ? let array:Array<MyBaseClass> = [obj1, obj2, obj3]
? ? for obj in array {
? ? ? ? if obj is MySubClassA {
? ? ? ? ? ? print((obj as! MySubClassA).count!)
? ? ? ? }else if obj is MySubClassB {
? ? ? ? ? ? print((obj as! MySubClassB).isBiger!)
? ? ? ? }else if obj is MyBaseClass {
? ? ? ? ? ? print(obj.name!)
? ? ? ? }
? ? }//打印hhhhh
? ? //3
? ? //true
使用類型轉(zhuǎn)換換時(shí)可以使用as?或者as!。as?是一種安全的轉(zhuǎn)換方式,會(huì)將值類型轉(zhuǎn)后的結(jié)果映射為optional類型,如果類型轉(zhuǎn)換成功,則值為原實(shí)例,如果類型轉(zhuǎn)換失敗,則會(huì)返回nil。
as!是強(qiáng)制轉(zhuǎn)換方式,默認(rèn)轉(zhuǎn)換完成后一定會(huì)成功,如果轉(zhuǎn)換失敗,會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤崩潰。使用as!轉(zhuǎn)換時(shí),必須保證實(shí)例的真實(shí)類型和要轉(zhuǎn)換的類型一致。
Any、AnyObject
AnyObject可以表示通用的對(duì)象類型,不能用來描述值類型。
Any可以表示任何類型,包含值類型和引用類型。
class MySubClassC {
}
class MySubClassD {
}
class MySubClassE {
}
? ? let obj4 = MySubClassC()
? ? let obj5 = MySubClassD()
? ? let obj6 = MySubClassE()
? ? let array2:Array<AnyObject> = [obj4, obj5, obj6]
? ? let array3:Array<Any> = [obj4, obj5, obj6, "hhhh"]
? ? for obj in array3 {
? ? ? ? if obj is MySubClassC {
? ? ? ? ? ? print("MySubClassC")
? ? ? ? }else if obj is MySubClassD{
? ? ? ? ? ? print("MySubClassD")
? ? ? ? }else if obj is MySubClassE{
? ? ? ? ? ? print("MySubClassE")
? ? ? ? }else{
? ? ? ? ? ? print("other")
? ? ? ? }
? ? }
泛型
泛型用來表達(dá)一種未定的數(shù)據(jù)類型,泛型可以作為函數(shù)參數(shù)。參數(shù)列表前用尖括號(hào)定義泛型,如果要定義多個(gè)泛型,用逗號(hào)分隔。作用域是函數(shù)部分。
func exchange<TempType>(param1: inout TempType, param2: inout TempType){
? ? let tmp = param1
? ? param1 = param2
? ? param2 = tmp
}
struct stack<ItemType> {
? ? var items:Array<ItemType> = []
? ? mutating func push(param:ItemType){
? ? ? ? self.items.append(param)
? ? }
? ? mutating func pop()->ItemType{
? ? ? ? return self.items.removeLast()
? ? }
}
擴(kuò)展
特性同oc
class MyBaseClass{
? ? var name:String
? ? var age:NSInteger
? ? init() {
? ? ? ? name = "hhhhh"
? ? ? ? age = 20
? ? }
}
extension MyBaseClass{
? ? var nameAndAge:String{
? ? ? ? return "\(name)\(age)"
? ? }
}
協(xié)議
protocol MyProtocol {
? ? var name:String{get set}
? ? func printName()
? ? static func logClassName()
}
class MyClass12: MyProtocol {
? ? var name: String
? ? init() {
? ? ? ? name = "hhhh"
? ? }
? ? func printName() {
? ? ? ? print(name)
? ? }
? ? static func logClassName() {
? ? ? ? print("MyClass12")
? ? }
}