Swift 語(yǔ)法淺聊
1. 簡(jiǎn)單值
使用** let 來(lái)聲明常量,使用 var **來(lái)聲明變量.
簡(jiǎn)單值數(shù)據(jù)類(lèi)型要首字母大寫(xiě).
var zl = 42
let zl = 24
let zl: Double = 100
2.類(lèi)型轉(zhuǎn)換
值永遠(yuǎn)不會(huì)被隱式轉(zhuǎn)換為其他類(lèi)型。如果你需要把一個(gè)值轉(zhuǎn)換成其他類(lèi)型牢贸,請(qǐng)顯式轉(zhuǎn)換:
字符串拼接用加號(hào)+,代表著轉(zhuǎn)換成字符串類(lèi)型的。
轉(zhuǎn)換成什么類(lèi)型的就放在前面舆蝴。
let label = "The width is"
let width = 94
let widthLabel = label + String(width)
3.字符串拼接
有一種更簡(jiǎn)單的把值轉(zhuǎn)換成字符串的方法:把值寫(xiě)到括號(hào)中,并且在括號(hào)之前寫(xiě)一個(gè)反斜杠题诵。例如:
swift中并無(wú)占位符洁仗,用** \() **來(lái)表示。
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit.”
4.定義數(shù)組 和 字典
使用方括號(hào)[]來(lái)創(chuàng)建數(shù)組和字典性锭,并使用下標(biāo)或者鍵(key)來(lái)訪問(wèn)元素赠潦。最后一個(gè)元素后面允許有個(gè)逗號(hào)。無(wú)@
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water”
***
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations”
要?jiǎng)?chuàng)建一個(gè)空數(shù)組或者字典草冈,使用初始化語(yǔ)法她奥。
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
PS:String:表示數(shù)組元素類(lèi)型,數(shù)據(jù)類(lèi)型首字母要大寫(xiě)
():表示構(gòu)造器怎棱,創(chuàng)建一個(gè)實(shí)例對(duì)象
Swift中兩個(gè)數(shù)組可用加號(hào)+直接相加哩俭,拼接成一個(gè)數(shù)組;而OC中不能數(shù)組直接相加拳恋。
String:key類(lèi)型
Float:value類(lèi)型
Swift中key可以是任意類(lèi)型携茂,而OC中必須是字符串類(lèi)型。
如果類(lèi)型信息可以被推斷出來(lái)诅岩,你可以用[]和[:]來(lái)創(chuàng)建空數(shù)組和空字典——就像你聲明變量或者給函數(shù)傳參數(shù)的時(shí)候一樣讳苦。
shoppingList = []
occupations = [:]
5.循環(huán) Control Flow控制流
使用if和switch來(lái)進(jìn)行條件操作,使用for-in吩谦、for鸳谜、while和repeat-while來(lái)進(jìn)行循環(huán)。包裹條件和循環(huán)變量括號(hào)可以省略式廷,但是語(yǔ)句體的大括號(hào)是必須的咐扭。
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
PS:
1、 只要變量名score滑废,并不寫(xiě)數(shù)據(jù)類(lèi)型蝗肪,因?yàn)閿?shù)組里能推斷出變量類(lèi)型。
2蠕趁、 if的判斷條件在Swift中不加括號(hào)了薛闪,
6.Switch-case分支語(yǔ)句
switch支持任意類(lèi)型的數(shù)據(jù)以及各種比較操作——不僅僅是整數(shù)以及測(cè)試相等。
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
PS:
1俺陋、每條分支語(yǔ)句不用寫(xiě)break語(yǔ)句豁延,運(yùn)行switch中匹配到的子句之后昙篙,程序會(huì)退出switch語(yǔ)句,并不會(huì)繼續(xù)向下運(yùn)行诱咏,所以不需要在每個(gè)子句結(jié)尾寫(xiě)break苔可。
2、case中條件不一定是確定值袋狞,可以是一個(gè)取值范圍焚辅,注意let在上述例子的等式中是如何使用的,它將匹配等式的值賦給常量x苟鸯。
3同蜻、分支中可以加判斷條件
4、where是判斷條件的關(guān)鍵字
7.Bool值
在if語(yǔ)句中倔毙,條件必須是一個(gè)布爾表達(dá)式——這意味著像if score { ... }這樣的代碼將報(bào)錯(cuò)埃仪,而不會(huì)隱形地與 0 做對(duì)比。
if中Bool值判斷條件必須補(bǔ)全陕赃,不能用==nil或者B羊取;
Swift中Bool值與OC中不同么库,只有true/false傻丝;OC中Bool值Yes代表非0,NO代表0.
8.區(qū)間
你可以在循環(huán)中使用** ..< **來(lái)表示范圍诉儒,也可以使用傳統(tǒng)的寫(xiě)法葡缰,兩者是等價(jià)的:
var firstForLoop = 0
for i in 0..<4 {
firstForLoop += i
}
print(firstForLoop)
var secondForLoop = 0
for var i = 0; i < 4; ++i {
secondForLoop += i
}
print(secondForLoop)
使用..<創(chuàng)建的范圍不包含上界,如果想包含的話需要使用 ... 忱反。
0..<4 -> 代表 [0, 4)
0...4 -> 代表 [0, 4]
9.可選值
一個(gè)可選的值是一個(gè)具體的值或者是nil以表示值缺失泛释。在類(lèi)型后面加一個(gè)問(wèn)號(hào)?來(lái)標(biāo)記這個(gè)變量的值是可選的温算。
在變量類(lèi)型名后加問(wèn)號(hào)怜校?,可選值僅僅針對(duì)數(shù)據(jù)類(lèi)型而已注竿∏炎拢可分為空值類(lèi)型nil和非空類(lèi)型。
var optionalString: String? = "Hello”
Swift中只有可選值為空巩割,空是一個(gè)明確值裙顽,這個(gè)值是nil。
處理變量的可選值時(shí)宣谈,你可以在操作(比如方法愈犹、屬性和子腳本)之前加?。如果?之前的值是nil蒲祈,?后面的東西都會(huì)被忽略甘萧,并且整個(gè)表達(dá)式返回nil萝嘁。否則梆掸,?之后的東西都會(huì)被運(yùn)行扬卷。在這兩種情況下,整個(gè)表達(dá)式的值也是一個(gè)可選值酸钦。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
10.解包與閉包
在變量名后面加一個(gè)感嘆號(hào)怪得!
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
等價(jià)于
if optionalName != nil {
greeting = "Hello, \(name)"
}
解包:把可選去掉,從而確定類(lèi)型
name卑硫!解包徒恋;而String! —> 自動(dòng)解包
可選綁定:
*1 可選值自動(dòng)解包
*2 解包出來(lái)不是nil空值,才會(huì)走if語(yǔ)句
閉包:相當(dāng)于OC中的block欢伏,在Swift中閉包比block強(qiáng)大入挣,可以傳函數(shù).
11.元組
是數(shù)據(jù)類(lèi)型(類(lèi)型中可以有一組數(shù)據(jù)),元組中數(shù)據(jù)可以是不同數(shù)據(jù)類(lèi)型硝拧。
(min: Int, max: Int, name: String)
12.函數(shù)
使用* func 來(lái)聲明一個(gè)函數(shù)径筏,使用名字和參數(shù)來(lái)調(diào)用函數(shù)。使用 -> *來(lái)指定函數(shù)返回值的類(lèi)型障陶。
使用元組來(lái)讓一個(gè)函數(shù)返回多個(gè)值滋恬。該元組的元素可以用名稱(chēng)或數(shù)字來(lái)表示。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
“ var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics([5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)
PS:OC中如果要返回多個(gè)值抱究,第一個(gè)是return返回帶回恢氯;第二個(gè)是指針帶回(傳參后指針賦值);
而Swift中用元組去返回多個(gè)值
func sumOf(numbers:Int… )->Int
其中Int…代表一組同類(lèi)型數(shù)據(jù)的數(shù)組
函數(shù)可以帶有可變個(gè)數(shù)的參數(shù)鼓寺,這些參數(shù)在函數(shù)內(nèi)表現(xiàn)為數(shù)組的形式:
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
函數(shù)可以嵌套勋拟。被嵌套的函數(shù)可以訪問(wèn)外側(cè)函數(shù)的變量,你可以使用嵌套函數(shù)來(lái)重構(gòu)一個(gè)太長(zhǎng)或者太復(fù)雜的函數(shù)妈候。
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
函數(shù)是第一等類(lèi)型敢靡,這意味著函數(shù)可以作為另一個(gè)函數(shù)的返回值。
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
函數(shù)也可以當(dāng)做參數(shù)傳入另一個(gè)函數(shù)州丹。
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, condition: lessThanTen
PS:Swift中函數(shù)可以嵌套醋安,OC中函數(shù)可以調(diào)用。
函數(shù)可作返回值(僅在意返回值數(shù)據(jù)類(lèi)型)使用墓毒,也可作參數(shù)傳入另一個(gè)函數(shù)(僅在意參數(shù)數(shù)據(jù)類(lèi)型)使用
函數(shù)實(shí)際上是一種特殊的閉包:它是一段能之后被調(diào)取的代碼吓揪。閉包中的代碼能訪問(wèn)閉包所建作用域中能得到的變量和函數(shù),即使閉包是在一個(gè)不同的作用域被執(zhí)行的 - 你已經(jīng)在嵌套函數(shù)例子中所看到所计。你可以使用{}來(lái)創(chuàng)建一個(gè)匿名閉包柠辞。使用in將參數(shù)和返回值類(lèi)型聲明與閉包函數(shù)體進(jìn)行分離。
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
13.對(duì)象和類(lèi)
使用* class *和類(lèi)名來(lái)創(chuàng)建一個(gè)類(lèi)主胧。類(lèi)中屬性的聲明和常量叭首、變量聲明一樣习勤,唯一的區(qū)別就是它們的上下文是類(lèi)。同樣焙格,方法和函數(shù)聲明也一樣图毕。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
PS:Swift中構(gòu)造器():創(chuàng)建新對(duì)象,
shape:實(shí)例對(duì)象眷唉,
Shape():類(lèi)名予颤,
()無(wú)參的構(gòu)造函數(shù),
var shape = Shape()
要?jiǎng)?chuàng)建一個(gè)類(lèi)的實(shí)例冬阳,在類(lèi)名后面加上括號(hào)蛤虐。使用點(diǎn)語(yǔ)法來(lái)訪問(wèn)實(shí)例的屬性和方法。
PS:Swift中屬性必須初始化肝陪,可有默認(rèn)值
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
這個(gè)版本的Shape類(lèi)缺少了一些重要的東西:一個(gè)構(gòu)造函數(shù)來(lái)初始化類(lèi)實(shí)例驳庭。使用init來(lái)創(chuàng)建一個(gè)構(gòu)造器。
PS:當(dāng)類(lèi)中屬性無(wú)默認(rèn)值(var name: String)氯窍,則需要使用* init() *來(lái)創(chuàng)建一個(gè)構(gòu)造器饲常。
如果你需要在刪除對(duì)象之前進(jìn)行一些清理工作,使用* deinit *創(chuàng)建一個(gè)析構(gòu)函數(shù)荞驴。
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
注意self被用來(lái)區(qū)別實(shí)例變量不皆。當(dāng)你創(chuàng)建實(shí)例的時(shí)候,像傳入函數(shù)參數(shù)一樣給類(lèi)傳入構(gòu)造器的參數(shù)熊楼。每個(gè)屬性都需要賦值——無(wú)論是通過(guò)聲明(就像numberOfSides)還是通過(guò)構(gòu)造器(就像name)霹娄。
14.繼承
子類(lèi)的定義方法是在它們的類(lèi)名后面加上父類(lèi)的名字(左邊子類(lèi)名繼承于右邊父類(lèi)名,父類(lèi)名要首字母大寫(xiě))鲫骗,用冒號(hào)分割犬耻。創(chuàng)建類(lèi)的時(shí)候并不需要一個(gè)標(biāo)準(zhǔn)的根類(lèi),所以你可以忽略父類(lèi)执泰。
子類(lèi)如果要重寫(xiě)父類(lèi)的方法的話枕磁,需要用* override *標(biāo)記——如果沒(méi)有添加override就重寫(xiě)父類(lèi)方法的話編譯器會(huì)報(bào)錯(cuò)。編譯器同樣會(huì)檢測(cè)override標(biāo)記的方法是否確實(shí)在父類(lèi)中术吝。
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
PS:Swift中在子類(lèi)構(gòu)造器中先初始化子類(lèi)中特有的屬性方法计济,然后再去調(diào)用父類(lèi)的構(gòu)造器init(); 而OC中重寫(xiě)父類(lèi)方法,需要先調(diào)用父類(lèi)[super …],在去擴(kuò)展子類(lèi)屬性方法排苍。
15.屬性
分為兩類(lèi):*1 計(jì)算屬性:關(guān)鍵字是set/get ; *2 存儲(chǔ)屬性:普通聲明屬性var width: Double = 0.0
- 總結(jié):* 只讀參數(shù)時(shí)沦寂,只有g(shù)et方法取值,無(wú)set方法改值存值淘衙。
get是必有的传藏,set可有可無(wú),但有set后必有g(shù)et。
當(dāng)無(wú)get/set毯侦,則是存儲(chǔ)屬性哭靖。
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triagle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
在perimeter的 setter 中,新值的名字是newValue侈离。你可以在set之后顯式的設(shè)置一個(gè)名字试幽。
注意EquilateralTriangle類(lèi)的構(gòu)造器執(zhí)行了三步:
*1 設(shè)置子類(lèi)聲明的屬性值
*2 調(diào)用父類(lèi)的構(gòu)造器
*3 改變父類(lèi)定義的屬性值。其他的工作比如調(diào)用方法霍狰、getters和setters也可以在這個(gè)階段完成抡草。
** 屬性監(jiān)視器:**
*1 如果你不需要計(jì)算屬性饰及,但是仍然需要在設(shè)置一個(gè)新值之前或者之后運(yùn)行代碼蔗坯,使用willSet{}和didSet{}。
*2 設(shè)置默認(rèn)值時(shí)就是存儲(chǔ)屬性燎含,無(wú)需做set方法改值存值宾濒,則也不會(huì)調(diào)用willSet{}和didSet{}。當(dāng)存儲(chǔ)屬性有默認(rèn)值后第一次不去調(diào)用willSet{}和didSet{}方法屏箍,當(dāng)它一旦改值使用set方法绘梦,就會(huì)調(diào)用調(diào)用willSet{}和didSet{}。
*3 willSet{}赴魁、didSet{} 和set卸奉、get不能共存。
*4 用didSet{} 用時(shí)nil空值會(huì)報(bào)錯(cuò)颖御,盡量用willSet{}榄棵。
懶加載中l(wèi)azy:
lazy var topics: NSMutableArray? = {
// 這里面進(jìn)行初始化配置
}()
** 注意:** 大括號(hào){}后有個(gè)()
1 計(jì)算屬性的值是不同的,是計(jì)算得來(lái)的潘拱,所以只能使用* var *來(lái)修飾疹鳄,不能使用let。
2 計(jì)算屬性本身是不能直接復(fù)制的芦岂,他是通過(guò)其他的變量/常量來(lái)計(jì)算結(jié)果得到的數(shù)據(jù)瘪弓。這個(gè)時(shí)候不可用成員變量_x的,Swift中無(wú)成員變量禽最。
16.枚舉
使用關(guān)鍵字* enum *來(lái)創(chuàng)建一個(gè)枚舉腺怯。就像類(lèi)和其他所有命名類(lèi)型一樣,枚舉可以包含方法川无。值類(lèi)型用assign
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue
在上面的例子中呛占,枚舉原始值的類(lèi)型是Int,所以你只需要設(shè)置第一個(gè)原始值舀透。剩下的原始值會(huì)按照順序賦值栓票。你也可以使用字符串或者浮點(diǎn)數(shù)作為枚舉的原始值。使用rawValue屬性來(lái)訪問(wèn)一個(gè)枚舉成員的原始值。
PS:枚舉名要首字母大寫(xiě)走贪。
枚舉內(nèi)枚舉值需用* case *開(kāi)頭佛猛。
枚舉內(nèi)可定義方法。
使用init?(rawValue:)初始化構(gòu)造器在原始值和枚舉值之間進(jìn)行轉(zhuǎn)換坠狡。
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}
枚舉里有原始值继找,枚舉的成員值是實(shí)際值(枚舉值),并不是原始值的另一種表達(dá)方法逃沿。實(shí)際上婴渡,以防原始值沒(méi)有意義,你不需要設(shè)置凯亮。
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
17.結(jié)構(gòu)體
使用關(guān)鍵字* struct *來(lái)創(chuàng)建一個(gè)結(jié)構(gòu)體边臼。結(jié)構(gòu)體和類(lèi)有很多相同的地方,比如方法和構(gòu)造器假消。它們之間最大的一個(gè)區(qū)別就是結(jié)構(gòu)體是傳值柠并,類(lèi)是傳引用。
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
PS:同樣可內(nèi)部定義一個(gè)函數(shù)富拗,OC中均不可臼予。定義枚舉的時(shí)候設(shè)置原始值。
結(jié)構(gòu)體和類(lèi)的區(qū)別:
在Swift中啃沪,
*1 類(lèi)可以繼承:引用類(lèi)型(類(lèi)引用—> 指針指向它粘拾,地址拷貝);而結(jié)構(gòu)體不可繼承:值類(lèi)型(賦值使用—>對(duì)象拷貝)创千。
*2 類(lèi)可以選擇部分屬性缰雇,而結(jié)構(gòu)體中屬性必須全部逐一構(gòu)造器。
import UIKit
var str = "Hello, playground"
// 引用類(lèi)型
class Person {
var age: Int!
}
var p = Person()
p.age = 20
let p2 = Person()
p2.age = 10
p = p2 // 引用:p指向p2地址
p.age // 10
p2.age // 10
p.age = 30 // 同一個(gè)地址签餐,地址里內(nèi)容改變
p2.age // 30
// 值類(lèi)型
struct Name {
var name: String?
}
var n = Name(name: "zl")
let n2 = Name(name: "dz")
n = n2 // 賦值:把n2的值賦給n
n.name // dz
n.name = "as" // Name
n2.name // dz
18.協(xié)議與擴(kuò)展
協(xié)議:使用* protocol *來(lái)聲明一個(gè)協(xié)議寓涨。
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
類(lèi)、枚舉和結(jié)構(gòu)體都可以實(shí)現(xiàn)協(xié)議氯檐。
Swift中可以定義屬性且不生成成員變量戒良;OC中只定義方法,協(xié)議不能定義屬性冠摄。
擴(kuò)展:使用* extension *來(lái)為現(xiàn)有的類(lèi)型添加功能糯崎,比如新的方法和計(jì)算屬性。你可以使用擴(kuò)展在別處修改定義河泳,甚至是從外部庫(kù)或者框架引入的一個(gè)類(lèi)型沃呢,使得這個(gè)類(lèi)型遵循某個(gè)協(xié)議。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
Swift中擴(kuò)展extension相當(dāng)于OC中的分類(lèi)category拆挥,但比它功能更強(qiáng)大薄霜。