你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開發--Swift語言3

iOS開發--Swift語言3

編輯:IOS開發綜合
協議

協議是對實例行為的一種約束,和ObjC類似,在Swift中可以定義屬性和方法(ObjC中之所以能定義屬性是因為@property的本質就是setter、getter方法)。和其他語言不同的是Swift中的協議不僅限於類的實現,它同樣可以應用於枚舉、結構體(如果只想將一個協議應用於類,可以在定義協議時在後面添加class關鍵字來限制其應用范圍)。

protocolNamed{ //定義一個實例屬性 varname:String{getset} //定義一個類型屬性 staticvarclassName:String{get} //定義構造方法 init(name:String) //定義一個實例方法 funcshowName() //定義一個類型方法 staticfuncshowClassName() } protocolScored{ varscore:Double{getset} } //Person遵循了Named協議 classPerson:Named{ //注意從Named協議中並不知道name是存儲屬性還是計算屬性,這裡將其作為存儲屬性實現 varname:String varage:Int=0 staticvarclassName:String{ return"Person" } //協議中規定的構造方法,必須使用required關鍵字聲明,除非類使用final修飾 requiredinit(name:String){ self.name=name } //遵循showName方法 funcshowName() { println("name=\(name)") } //遵循showClassName方法 staticfuncshowClassName() { println("Class name is \"Person\"") } } //Student繼承於Person並且實現了Scored協議 classStudent:Person,Scored{ varscore:Double=0.0 init(name:String,score:Double){ self.score=score super.init(name:name) } //由於上面自定義了構造方法則必須實現協議中規定的構造方法 requiredinit(name:String) { super.init(name:name) } functest(){ println("\(self.name) is testing.") } } varp=Person(name:"Kenshin Cui") p.showName()//結果:name=Kenshin Cui println("className=\(Person.className)")//結果:className=Person Person.showClassName()//結果:Class name is "Person" p.age=28 vars:Named=Student(name:"Kaoru",score:100.0)//盡管這裡將s聲明為Named類型,但是運行時仍然可以正確的解析(多態),但是注意此時編譯器並不知道s有test方法,所以此時調用test()會報錯 s.showName() //在下面的函數中要求參數stu必須實現兩個協議 funcshowMessage(stu:protocol){ println("name=\(stu.name),score=\(stu.score)") } vars2=Student(name:"Tom",score:99.0) showMessage(s2)//結果:name=Tom,age=99.0 //檢測協議 letb1=sisScored//判斷p是否遵循了Scored協議 ifb1{ println("s has score property.") } //類型轉化 iflets3=sas?Scored{//如果s轉化成了Scored類型則返回實例,否則為nil println("s3' score is \(s3.score)")//結果:s3' score is 100.0 } lets4=sas!Scored//強制轉換,如果轉化失敗則報錯 println("s4' score is \(s4.score)")//結果:s4' score is 100.0

協議中雖然可以指定屬性的讀寫,但即使協議中規定屬性是只讀的但在使用時也可以將其實現成可讀寫的;

Swift的協議中可以約定屬性是實例屬性還是類型屬性、是讀寫屬性還是只讀屬性,但是不能約束其是存儲屬性還是計算屬性;

協議中的類型屬性和類型方法使用static修飾而不是class(盡管對於類的實現中類型屬性、類型方法使用class修飾);

協議中約定的方法支持可變參數,但是不支持默認參數;

協議中約定的構造方法,在實現時如果不是final類則必須使用require修飾(以保證子類如果需要自定義構造方法則必須覆蓋父類實現的協議構造方法,如果子類不需要自定義構造方法則不必);

一個協議可以繼承於另外一個或多個協議,一個類只能繼承於一個類但可以實現多個協議;

協議本身就是一種類型,這也體現除了面向對象的多態特征,可以使用多個協議的合成來約束一個實例參數必須實現某幾個協議;

擴展

Swift中的擴展就類似於ObjC中的分類(事實上在其他高級語言中更多的稱之為擴展而非分類),但是它要比分類強大的多,它不僅可以擴展類還可以擴展協議、枚舉、結構體,另外擴展也不局限於擴展方法(實例方法或者類型方法),還可以擴展便利構造方法、計算屬性、下標腳本、

classPerson{ varfirstName:String,lastName:String varage:Int=0 varfullName:String{ get{ returnfirstName+" "+lastName } } init(firstName:String,lastName:String){ self.firstName=firstName self.lastName=lastName } funcshowMessage(){ println("name=\(fullName),age=\(age)") } } extensionPerson{ //只能擴展便利構造方法,不能擴展指定構造方法 convenienceinit(){ self.init(firstName:"",lastName:"") } //只能擴展計算屬性,無法擴展存儲屬性 varpersonInfo:String{ return"firstName=\(firstName),lastName=\(lastName),age=\(age)"; } //擴展實例方法 funcsayHello(){ println("hello world.") } //嵌套類型 enumSkinColor{ caseYellow,White,Black } //擴展類型方法 staticfuncskin()->[SkinColor]{ return[.Yellow,.White,.Black] } } varp=Person() p.firstName="Kenshin" p.lastName="Cui" p.age=28 println(p.personInfo)//結果:firstName=Kenshin,lastName=Cui,age=28 p.sayHello()//結果:hello world. Person.skin()

枚舉和結構體

結構體

結構體和類是構造復雜數據類型時常用的構造體,在其他高級語言中結構體相比於類要簡單的多(在結構體內部僅僅能定義一些簡單成員),但是在Swift中結構體和類的關系要緊密的多,這也是為什麼將結構體放到後面來說的原因。Swift中的結構體可以定義屬性、方法、下標腳本、構造方法,支持擴展,可以實現協議等等,很多類可以實現的功能結構體都能實現,但是結構體和類有著本質區別:類是引用類型,結構體是值類型。

structPerson{ varfirstName:String varlastName:String varfullName:String{ returnfirstName+" "+lastName } varage:Int=0 //構造函數,如果定義了構造方法則不會再自動生成默認構造函數 // init(firstName:String,lastName:String){ // self.firstName=firstName // self.lastName=lastName // } funcshowMessage(){ println("firstName=\(firstName),lastName=\(lastName),age=\(age)") } //注意對於類中聲明類型方法使用關鍵字class修飾,但結構體裡使用static修飾 staticfuncshowStructName(){ println("Struct name is \"Person\"") } } //注意所有結構體默認生成一個全員逐一構造函數,一旦自定義構造方法,這個默認構造方法將不會自動生成 varp=Person(firstName:"Kenshin",lastName:"Cui",age:28) println(p.fullName)//結果:Kenshin Cui p.showMessage()//結果:firstName "Kenshin", lastName "Cui", age 28 Person.showStructName()//結果:Struct name is "Person" //由於結構體(包括枚舉)是值類型所以賦值、參數傳遞時值會被拷貝(所以下面的實例中p2修改後p並未修改,但是如果是類則情況不同) varp2=p p2.firstName="Tom" println(p2.fullName)//結果:Tom Cui println(p.fullName)//結果:Kenshin Cui

默認情況下如果不自定義構造函數那麼將自動生成一個無參構造函數和一個全員的逐一構造函數;

由於結構體是值類型,所以它雖然有構造函數但是沒有析構函數,內存釋放系統自動管理不需要開發人員過多關注;

類的類型方法使用class修飾(以便子類可以重寫),而結構體、枚舉的類型方法使用static修飾(補充:類方法也可以使用static修飾,但是不是類型方法而是靜態方法;另外類的存儲屬性如果是類型屬性使用static修飾,而類中的計算屬性如果是類型屬性使用class修飾以便可以被子類重寫;換句話說class作為“類型范圍作用域”來理解時只有在類中定義類型方法或者類型計算屬性時使用,其他情況使用static修飾[包括結構體、枚舉、協議和類型存儲屬性]);

類的實例通常稱之為“對象”,而在Swift中結構體也可以有實例,因此對於很多二者都可以實現的功能,在文中稱之為實例而沒有使用對象的概念。

枚舉

在其他語言中枚舉本質就是一個整形,只是將這組相關的值組織起來並指定一個有意義的名稱。但是在Swift中枚舉不強調一個枚舉成員必須對應一個整形值(當然如果有必要仍然可以指定),並且枚舉類型的可以是整形、浮點型、字符、字符串。首先看一下枚舉的基本使用:

//注意Swift中的枚舉默認並沒有對應的整形值,case用來定義一行新的成員,也可以將多個值定義到同一行使用逗號分隔,例如:case Spring,Summer,Autumn,Winter enumSeason{ caseSpring caseSummer caseAutumn caseWinter } vars=Season.Spring //一旦確定了枚舉類型,賦值時可以去掉類型實現簡寫 s= .Summer switchs{ case.Spring://由於Swift的自動推斷,這裡仍然可以不指明類型 println("spring") case.Summer: println("summer") case.Autumn: println("autumn") default: println("winter") }

事實上Swift中也可以指定一個值和枚舉成員對應,就像其他語言一樣(通常其他語言的枚舉默認就是整形),但是Swift又不局限於整形,它可以是整形、浮點型、字符串、字符,但是原始值必須是一種固定類型而不能存儲多個不同的類型,同時如果原始值為整形則會像其他語言一樣默認會自動遞增。

//指定原始值(這裡定義成了整形) enumSeason:Int{ caseSpring=10//其他值會默認遞增,例如Summer默認為11,如果此處也不指定值會從0開始依次遞增 caseSummer caseAutumn caseWinter } varsummer=Season.Summer //使用rawValue訪問原始值 println("summer=\(summer),rawValue=\(summer.rawValue)") //通過原始值創建枚舉類型,但是注意它是一個可選類型 varautumn=Season(rawValue:12) //可選類型綁定 ifletnewAutumn=autumn{ println("summer=\(newAutumn),rawValue=\(newAutumn.rawValue)") }

如果一個枚舉類型能夠和一些其他類型的數據一起存儲起來往往會很有用,因為這可以讓你存儲枚舉類型之外的信息(類似於其他語言中對象的tag屬性,但是又多了靈活性),這在其他語言幾乎是不可能實現的,但是在Swift中卻可以做到,這在Swift中稱為枚舉類型相關值。要注意的是相關值並不是原始值,原始值需要事先存儲並且只能是同一種類型,但是相關值只有創建一個基於枚舉的變量或者常量時才會指定,並且類型可以不同(原始值更像其他語言的枚舉類型)。

//相關值 enumColor{ caseRGB(String)//注意為了方便演示這裡沒有定義成三個Int類型(例如: RGB(Int,Int,Int))而使用16進制字符串形式 caseCMYK(Float,Float,Float,Float) caseHSB(Int,Int,Int) } varred=Color.RGB("#FF0000") vargreen=Color.CMYK(0.61,0.0,1.0,0.0) varblue=Color.HSB(240,100,100) switchred{ case.RGB(letcolorStr): println("colorStr=\(colorStr)") caselet.CMYK(c,m,y,k): println("c=\(c),m=\(m),y=\(y),k=\(k)") caselet.HSB(h,s,b): println("h=\(h),s=\(s),b=\(b)") }

上面提到其實枚舉也有一些類型和結構體的特性,例如計算屬性(包括類型屬性,枚舉只能定義計算屬性不能定義存儲屬性,存儲屬性只能應用於類和結構體)、構造方法(其實上面使用原始值創建枚舉的例子就是一個構造方法)、方法(實例方法、類型方法)、下標腳本 。

enumSeason:Int{ caseSpring=0,Summer,Autumn,Winter //定義計算屬性 vartag:Int{ returnself.rawValue } //類型屬性 staticvarenumName:String{ return"Season" } // //定義構造方法,注意在枚舉的構造函數中則必須保證self有值(正如類的構造方法必須保證其存儲屬性有值一樣) // init(prefix:String){ // switch prefix.lowercaseString { // case "sp": // self = .Spring // case "su": // self = .Summer // case "au": // self = .Autumn // default: // self = .Winter // } // } //其實上面的構造器有些不合理,那就是default就是Winter,事實上這類構造器可能傳任何參數,此時可以使用可失敗構造函數來解決 //可失敗構造函數返回nil(盡管Swift中構造函數是不返回值的,但是此時約定返回nil代表構造失敗) init?(prefix:String){ switchprefix.lowercaseString{ case"sp": self= .Spring case"su": self= .Summer case"au": self= .Autumn case"wi": self= .Winter default: returnnil } } //定義實例方法 funcshowMessage(){ println("rowValue=\(self.rawValue)") } //定義類型方法 staticfuncshowEnumName(){ println("Enum name is \"Season\"") } } varsummer=Season.Summer println(summer.tag)//結果:1 println(Season.enumName)//結果:Season Season.showEnumName()//結果:Enum name is "Season" summer.showMessage()//結果:rowValue=1 ifletspring=Season(prefix:"au") {//可選綁定,構造函數返回值可能為nil println(spring.tag)//結果:2 }

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved