swift無疑是IOS程序員的未來,但是目前蘋果公司還在不端更新和改變swift,甚至在語法層面還在不斷探索,雖然xcode提供一些直接適配新版本swift語法的快捷鍵,但給我們學習不免造成一些影響,這里是基于swift3.0和oc的一些基礎性知識的比較。
####一。基礎部分
1.Swift的類型是在C和Objective-C的基礎上提出的,Int是整型;Double和Float是浮點型;Bool是布爾型;String是字符串。Swift還有兩個有用的集合類型,Array和Dictionary,(類型第一個字母大寫)
2.Swift還增加了Objective-C中沒有的類型比如元組(Tuple)。元組可以讓你創建或者傳遞一組數據,比如作為函數的返回值時,你可以用一個元組可以返回多個值。
元組(tuples)把多個值組合成一個復合值。元組內的值可以使任意類型,并不要求是相同類型。
let?http404Error?=(404,"Not?Found")
(404,"Not Found")元組把一個Int值和一個String值組合起來表示HTTP狀態碼的兩個部分:一個數字和一個人類可讀的描述。這個元組可以被描述為“一個類型為(Int,String)的元組”。
你可以把任意順序的類型組合成一個元組,這個元組可以包含所有類型。只要你想,你可以創建一個類型為(Int,Int,Int)或者(String,Bool)或者其他任何你想要的組合的元組。
你還可以通過下標來訪問元組中的單個元素,下標從零開始:
println("The?status?code?is?\(http404Error.0)")
你可以在定義元組的時候給單個元素命名:
let?http200Status?=(statusCode:?200,description:?"OK")
給元組中的元素命名后,你可以通過名字來獲取這些元素的值:
println("The?status?code?is?\(http200Status.statusCode)")
注意:元組在臨時組織值的時候很有用,但是并不適合創建復雜的數據結構。如果你的數據結構并不是臨時使用,請使用類或者結構體而不是元組。
3.Swift還增加了可選(Optional)類型,用于處理值缺失的情況。可選表示“那兒有一個值,并且它等于x”或者“那兒沒有值”。可選有點像在Objective-C中使用nil,但是它可以用在任何類型上,不僅僅是類。可選類型比Objective-C中的nil指針更加安全也更具表現力,它是Swift許多強大特性的重要組成部分。
Swift定義的常量和變量是沒有默認值的,所以引入了可選的概念,用?修飾變量,標示該變量的值可能為空也可能為某個值,然后獲取的時候用!強制解析,此時必須有值,否則報運行時錯誤。
比如你定義一個String類型的變量
var str:String?
str="ass"
print("str=\(str!)")
如果不使用!強制解析,可以使用可選綁定(optional binding)來判斷可選是否包含值,如果包含就把值賦給一個臨時常量或者變量。
if let realstr = str
{
print("realstr=\(realstr)")
}else
{
print("str為空")
}
有的函數的返回值就是可選類型,默認是使用?修飾的,也需要!強制解析或者可選綁定解析。
let?convertedNumber?=?possibleNumber.toInt()
//?convertedNumber被推測為類型"Int?",或者類型"optional?Int"
ifconvertedNumber?{
println("\(convertedNumber!)")
}else{
println("could?not?be?converted")
}
隱式解析可選
有時候在程序架構中,第一次被賦值之后,可以確定一個可選總會有值。在這種情況下,每次都要判斷和解析可選值是非常低效的,因為可以確定它總會有值。
這種類型的可選被定義為隱式解析可選(implicitly unwrapped optionals)。把想要用作可選的類型的后面的問號(String?)改成感嘆號(String!)來聲明一個隱式解析可選。
let?possibleString:?String?=?"An?optional?string."
println(possibleString!)//需要驚嘆號來獲取值
//輸出"An?optional?string."
let?assumedString:?String!?=?"An?implicitly?unwrapped?optional?string."
println(assumedString)//不需要感嘆號
//輸出"An?implicitly?unwrapped?optional?string."
自判斷鏈接
自判斷鏈接(Optional Chaining)是一種可以請求和調用屬性、方法及子腳本的過程,它的自判斷性體現于請求或調用的目標當前可能為空(nil)。如果自判斷的目標有值,那么調用就會成功;相反,如果選擇的目標為空(nil),則這種調用將返回空(nil)。多次請求或調用可以被鏈接在一起形成一個鏈,如果任何一個節點為空(nil)將導致整個鏈失效。
如果用!解析一個可選類型為空時會報運行時異常
如果改用?解析就可以避免
print(stu.room!.person.name)
room==nil所以報運行時錯誤
print(stu.room?.person.name)
就打印nil
更正規的寫法可以使用if let
如果numberOfRooms為Int類型,john.residence?.numberOfRooms就是Int?類型
iflet?roomCount?=?john.residence?.numberOfRooms
{
}else
{
}
如果printNumberOfRooms()返回值為Void類型,john.residence?.printNumberOfRooms()就是Void?類型
ifjohn.residence?.printNumberOfRooms()
{
}else
{
}
4.常量的值一旦設定就不能改變,而變量的值可以隨意更改。常量和變量必須在使用前聲明,用let來聲明常量,用var來聲明變量。所謂改變,對于基本數據類型而言,值改變就是改變,而對于引用數據類型而言,指針指向改變才是改變。
Swift中整數(Integer)、浮點數(floating-point)、布爾值(Booleans)、字符串(string)、數組(array)和字典(dictionaries),都是值類型,并且都是以結構體的形式在后臺所實現。
eg: var arr=[“a”,”b”,”c”]
var arrcopy =arr
//此時arr-“a,b,c”arrcopy-“abc”
arrcopy[0]=“fuck”
//此時arr-“a,b,c”arrcopy-“fuck,b,c”
class Person
{
varname:String=“a”
}
var arr=[person1,person2,person3]
var arrcopy =arr
//此時arr,arrcopy指向一塊區域,一同改變
5.類型別名(type aliases)就是給現有類型定義另一個名字。你可以使用typealias關鍵字來定義類型別名。
當你想要給現有類型起一個更有意義的名字時,類型別名非常有用。假設你正在處理特定長度的外部資源的數據:
typealias?AudioSample?=?UInt16
定義了一個類型別名之后,你可以在任何使用原始名的地方使用別名:
varmaxAmplitudeFound?=?AudioSample.min
6.控制流
兩種形式的for循環
//傳統獲取index的語法
for i in 0…10
{
}
//快速訪問對象的語法
for obj in arr
{
}
二.函數
普通函數定義和使用
func add(param1:String,param2:String)->String
{
return param1+param2
}
print(add(param1: "w",param2: "q"))
可以給參數添加默認值,使用時也可以不傳此參數
func add2(param1:String,param2:String="q")->String
{
return param1+param2
}
print(add2(param1: "w"))
inout修飾函數參數
變量形參只能在函數本身內改變。如果你想讓函數改變形參值,并想要在函數調用結束后保持形參值的改變,那你可以把形參定義為in-out形參。
func change(param:inout String)
{
param="wowo"
}
var kaka:String="kaka"
change(param: &kaka)
print(kaka)//此時kaka=“wowo”
復雜函數定義和使用
函數可以作為形參和另一個函數的返回值
三.類
class Person: NSObject {
//普通屬性方法定義
var name:String?
func sayHi(mes:String)->String{
return "person\(mes)"
}
//靜態屬性方法定義(屬性用static修飾,方法用static或class修飾)
static var age:String?
class func sayMessage()
{
print("i am person\(age!)")
}
}
屬性
lazy修飾的屬性必須初始化它會在使用該屬性的時候才去執行初始化的代碼一般用在消耗不少時間的變量上比如文件打開
lazy特性;局部范圍的常量或變量不會延遲計算。
set get方法
//既有set又有get方法
var firstName:String
{
get
{
return "first"+self.name!
}
//newValue代表set參數值
set
{
self.name="setName:"+newValue
}
}
//只有get方法
var lastName:String
{
return "last"+self.name!
}
屬性監視器
willSet didSet方法
willSet在設置新的值之前調用
didSet在新的值被設置之后立即調用
//需要設置默認值
var idcard:Double = 0.0
{
willSet
{
print("willSet")
}
didSet
{
print("didSet")
}
}
繼承
如果子類實現和父類相同的方法或者屬性就是重寫。必須用overriding關鍵字表明。
重寫overriding方法
class Student: Person {
override func sayHello(mes: String)-> String {
//可以使用super關鍵字調用父類方法
return super.sayHello(mes:mes)
}
}
重寫overriding屬性
override var name: String?
{
set
{
}
get
{
return super.name
}
}
原則:你可以將一個繼承來的只讀屬性重寫為一個讀寫屬性,只需要你在重寫版本的屬性里提供getter和setter即可。但是,你不可以將一個繼承來的讀寫屬性重寫為一個只讀屬性。
防止重寫
你可以通過把方法,屬性或附屬腳本標記為final來防止它們被重寫
構造方法
與Objective-C中的構造器不同,Swift的構造器無需返回值,它們的主要任務是保證新實例在第一次使用前完成正確的初始化。
構造器分位指定構造器和便利構造器
原則:指定構造器是向上調用的,便利構造器是橫向調用的.
規則1:指定構造器必須調用其父類的指定構造器
規則2:便利構造器必須調用同一類中調用的其他構造器
規則3:便利構造器必須以調用一個指定構造器結束
//指定構造器(默認構造方法),因為父類也有該方法,所以用override
override init()
{
super.init()
print("Student init")
}
//指定構造器(自定義構造方法,父類沒有該方法,不需要override)
init(size:Double)
{
super.init(size: size)
print("Student init with size")
}
//便利構造器(使用關鍵詞convenience,需要調用自己的構造方法)
convenience init(size:Double,friendNums:Double){
self.init(size:size)
self.friendNums=friendNums
}
類擴展
相當于OC分類
Swift中的擴展可以:
1.添加計算型屬性和計算靜態屬性
注意:擴展可以添加新的計算屬性,但是不可以添加存儲屬性,也不可以向已有屬性添加屬性觀測器(property observers)
2.定義實例方法和類型方法
3.提供新的構造器
4.定義下標
5.定義和使用新的嵌套類型
6.使一個已有類型符合某個接口
extension Room
{
var newSize:Double
{
return self.size+100
}
func sayExtensionRoom(){
print("sayExtensionRoom\(self.newSize)")
}
}
協議
四.自動引用計數
總體基本和oc一致,在解決循環引用的問題有點區別。
可以使用弱引用weak和無主引用unowned修飾一方變量。
1.兩個屬性的值都可能是nil,并有可能產生強引用環。這種場景下適合使用弱引用。
var a:A?
weak b:B?
2.一個屬性可以是nil,另外一個屬性不允許是nil,并有可能產生強引用環。這種場景下適合使用無主引用。
var a:A?
unowned b:B
override init(){
self.b=B()
}
3.兩個屬性都必須有值,且初始化完成后不能為nil。這種場景下,則要一個類用無主引用屬性,另一個類用隱式展開的可選屬性。
var a:A!
override init(){
self.a=A()
}
unowned b:B
override init(){
self.b=B()
}
五.類型轉換
檢查類型
用類型檢查操作符(is)來檢查一個實例是否屬于特定子類型。類型檢查操作符返回true若實例屬于那個子類型,若不屬于返回false。
library中添加Movie和Song
foriteminlibrary?{
ifitem?is?Movie?{
++movieCount
}elseifitem?is?Song?{
++songCount
}
}
向下轉型(簡稱下轉)
某類型的一個常量或變量可能在幕后實際上屬于一個子類。你可以相信,上面就是這種情況。你可以嘗試向下轉到它的子類型,用類型轉換操作符(as)
如果強制轉型肯定成功,可以使用as!,如果使用as?,那么返回結果成功則為該轉的類型,失敗則為空,此時可以使用if let來接收判斷
Any和AnyObject的轉換
Swift為不確定類型提供了兩種特殊類型別名:
1. AnyObject可以代表任何class類型的實例。
2. Any可以表示任何類型(基礎類型和class類型),除了方法類型(function types)。
六.閉包
Swift中的閉包與C和Objective-C中的blocks有點類似。
閉包表達式語法
{(parameters)->?returnTypein
statements
}
捕獲
閉包可以在其定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。
//makeIncrementor函數返回值是一個()->Int類型的函數
func makeIncrementor(amount: Int)->()-> Int {
var runningTotal = 0
func incrementor()-> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
//閉包捕獲amount參數的值,然后每次都可以使用
let incrementByTen = makeIncrementor(amount: 10)
print(incrementByTen())//10
print(incrementByTen())//20
print(incrementByTen())//30
七.應用
swift讀取文件為String類型
let path:String = Bundle.main.path(forResource: "demo2.js",ofType:nil)!
if let spath = try?String.init(contentsOf: URL.init(fileURLWithPath: path),encoding:String.Encoding.utf8)
{
}else
{
}
2017-2-8 遷出自備忘錄