[TOC]
字典集合
字典:字典(存放鍵值對組合的容器)字典中的每個元素都是由兩部分構(gòu)成的, 冒號前面是鍵冒號后面是值
集合:Swift中的Set類型被寫為Set<T>,這里的T表示Set中允許存儲的類型仙蚜。
var dict: [String: String] = ["a": "你", "b": "好"]
通過鍵獲取對應(yīng)的值(可空類型, 因為給的鍵有可能沒有與之對應(yīng)的值)
print(dict["hello"]!)// key ---> value
print(dict["abcxyz"])
元素的添加修改刪除
dict["c"] = "嗎"http:// 添加元素
dict.removeValueForKey("hello")// 刪除元素
dict["hello"] = nil //刪除元素的值
dict["c"] = "你好" //元素值的修改
遍歷
for value in dict.values {
print(value)// 遍歷字典中所有的值
}
for key in dict.keys {
print("\\(key) ---> \\(dict[key])") //遍歷字典中所有的鍵
}
for (key, value) in dict {
print("\\(key) ---> \\(value)")// 直接通過一個元組獲得字典中的鍵和值(原始類型)
}
集合的創(chuàng)建
var a: Set<Int> = [1, 2, 3, 4, 2, 5]
集合元素的修改
a.insert(100) // 添加元素
a.remove(2) // 刪除元素
集合的操作
var b: Set<Int> = [3, 5, 7, 9, 11]
var a: Set<Int> = [1, 2, 3, 4, 2, 5]
print(a.intersect(b)) // 交集(a和b都有的元素)
print(a.union(b)) // 并集(a和b的所有元素)
print(a.subtract(b)) // 差集(a有b沒有的元素)
let c: Set<Int> = [1, 3]
print(c.isSubsetOf(a)) // 判斷c是不是a的子集
print(a.isSupersetOf(c)) // 判斷a是不是c的超集
let d: Set<Int> = [2, 1000, 10000]
print(a.isDisjointWith(d)) // 判斷兩個集合是否相交
函數(shù)
定義函數(shù):func 函數(shù)名(參數(shù)列表) -> 返回類型 { 函數(shù)的執(zhí)行體 }
Swift中函數(shù)的參數(shù)可以設(shè)定默認(rèn)值 如果調(diào)用函數(shù)的時候沒有給該參數(shù)賦值就直接使用默認(rèn)值
func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {//Bool 默認(rèn)值是false ->返回的類型
if alreadyGreeted {
return "你好, " + personName + "!"
}
函數(shù)的參數(shù)名:函數(shù)名(外部參數(shù)名 內(nèi)部參數(shù)名: 類型, 外部參數(shù)名 內(nèi)部參數(shù)名: 類型)
如果不寫外部參數(shù)名那么內(nèi)部參數(shù)名也是外部參數(shù)名
可以使用_來作為外部參數(shù)名表示省略外部參數(shù)名
func myMin(a x: Int, b y: Int) -> Int {//a,b外部參數(shù)名 x志鞍,y內(nèi)部參數(shù)名
return x < y ? x : y
}
調(diào)用函數(shù)的時候要寫函數(shù)的外部參數(shù)名
print(myMin(a: 3, b: 5))
調(diào)用函數(shù): 函數(shù)名(參數(shù)值)婴噩, 調(diào)用Swift的函數(shù)時, 在默認(rèn)情況下從第二個參數(shù)開始需要寫參數(shù)名
print(sayHello("小明", alreadyGreeted: true))
如果沒有給第二個參數(shù)賦值那么就直接使用默認(rèn)值false
print(sayHello("Jack")
Swift中函數(shù)的參數(shù)列表可以是可變參數(shù)列表(參數(shù)的個數(shù)是任意多個)
func sum(nums: Int...) -> Int {
var total = 0
for num in nums {
total += num
}
return total
}
print(sum())
print(sum(999))
print(sum(1, 2, 3))
print(sum(90, 82, 37, 68, 55, 11, 99))
在Swift中函數(shù)是一種類型,這也就意味著函數(shù)可以作為變量或常量的類型,同理函數(shù)也可以作為另一個函數(shù)的參數(shù)或返回值
func foo(array: [Int], fn: (Int, Int) -> Int) -> Int {
var sum = array[0]
for x in array[1..<array.count] {
sum = fn(sum, x)
}
return sum
}
閉包
閉包:閉包是功能性自包含模塊订框,可以在代碼中被傳遞和使用
傳入匿名函數(shù)(閉包)
如果函數(shù)的最后一個參數(shù)是閉包可以寫成尾隨閉包的形式
也就是將閉包放到函數(shù)參數(shù)的圓括號外面寫在一對花括號中
如果函數(shù)后面有尾隨閉包且函數(shù)的圓括號中沒有參數(shù)
那么函數(shù)的圓括號也可以省略(僅限于有尾隨閉包的場景)
1.1 完整的閉包寫法
print(foo(a, fn: { (a, b) -> Int in
return a + b
}))
1.2 省略掉類型和不必要的括號
print(foo(a, fn: { a, b in a + b }))
1.3 省略參數(shù)名
print(foo(a, fn: { $0 + $1 }))
1.4 尾隨閉包
print(foo(a) { (a, b) -> Int in
return a + b
})
類
類
發(fā)現(xiàn)類
- 在對問題的描述中找名詞和動詞
- 名詞會成為類或者類中的屬性 動詞會成為類中的方法
定義類
- 數(shù)據(jù)抽象(屬性)
- 行為抽象(方法)
- 初始化方法
訪問修飾符
public (公開)
internal (內(nèi)部的) - 默認(rèn)
private (私有)
存儲屬性通常是private的 因為數(shù)據(jù)要保護起來
方法一般是public的 因為方法是對象接受的消息
如果自定義的類沒有打算在其他項目中使用 可以不寫訪問修飾符
直接使用默認(rèn)的internal修飾符表示在本項目中公開對其他項目私有
class Circle {
// stored property
// 存儲屬性(保存和圓相關(guān)的數(shù)據(jù)的屬性)
var center: Point
var radius: Double
init(center: Point, radius: Double) {
self.center = center
self.radius = radius
}
// 通常獲得某個計算出的值的方法都可以設(shè)計成計算屬性
// computational property
// 計算屬性(通過對存儲屬性做運算得到的屬性)
var perimeter: Double {
// 圓的周長是一個只讀屬性
// 所以此處只有g(shù)et{}沒有set{}
get { return 2 * M_PI * radius }
}
var area: Double {
get { return M_PI * radius * radius }
}
}
步驟1: 定義類(如果你要用的類蘋果已經(jīng)提供了就直接進(jìn)入第2步)
定義類就可以創(chuàng)建出新的類型
例:學(xué)生類
class Student {
// 變量定義到類的外面就叫變量 - variable
// 變量定義到類的里面就叫屬性 - property
// 數(shù)據(jù)抽象 - 找到和學(xué)生相關(guān)的屬性(找名詞)
var name: String
var age: Int
// 初始化方法(構(gòu)造方法/構(gòu)造器) - constructor
init(name: String, age: Int) {
self.name = name
self.age = age
}
// 我們可以在一個類中定義多個初始化方法
// 便利初始化方法 / 便利構(gòu)造器
// 調(diào)用了其他的初始化方法的初始化方法
convenience init(s:(String,Int)) {
self.init(name: s.0, age: s.1)
}
convenience init() {
self.init(name: s.0, age: s.1)
}
// 指派初始化方法 / 指派構(gòu)造器
// 被其他初始化方法調(diào)用的初始化方法
init(x: Double, y: Double) {
self.x = x
self.y = y
}
// 函數(shù)寫到類的外面就叫函數(shù) - function
// 函數(shù)寫到類的里面就叫方法 - method
// 行為抽象 - 找到和學(xué)生相關(guān)的方法(找動詞)
func study(courseName: String) {
print("\\(name)正在學(xué)習(xí)\\(courseName).") }
}
}
步驟2: 創(chuàng)建對象(調(diào)用初始化方法)
let stu1 = Student(name: "小明", age: 35)
步驟3: 給對象發(fā)消息(通過給對象發(fā)消息來解決問題)
tu1.study("Swift程序設(shè)計")
短除法(歐幾里得算法)
x和y的最大公約數(shù)跟y%x和x的最大公約數(shù)是一樣的
Greatest Common Divisor
func gcd(x: Int, _ y: Int) -> Int {
if x > y {
return gcd(y, x)
}
else if y % x != 0 {
return gcd(y % x, x)
}
else {
return x
}
}
繼承
繼承: 從已有的類創(chuàng)建新類的過程
提供繼承信息的稱為父類(超類/基類)
得到繼承信息的稱為子類(派生類/衍生類)
通常子類除了得到父類的繼承信息還會增加一些自己特有的東西
所以子類的能力一定比父類更強大
繼承的意義在于子類可以復(fù)用父類的代碼并且增強系統(tǒng)現(xiàn)有的功能
創(chuàng)建父類
enum Gender { //枚舉
case Male
case Female
}
class Person {
var name: String
var age: Int
var gender: Gender
init(name: String, age: Int, gender: Gender) {
self.name = name
self.age = age
self.gender = gender
}
func eat() {
print("\\(name)正在吃飯.")
}
}
創(chuàng)建子類
class Student: Person {//:Person 繼承人類(父類)
var major: String//課程
init(name: String, age: Int, gender: Gender, major: String) {
self.major = major
super.init(name: name, age: age, gender: gender)
}
func study(courseName: String) { //學(xué)生學(xué)習(xí)的方法
print("\\(name)是\\(major)專業(yè)的學(xué)生.")
print("\\(gender == .Male ? "他" : "她")正在學(xué)習(xí)\\(courseName).")
}
}
創(chuàng)建對象
let per = Person(name: "小明", age: 25, gender: .Male)//創(chuàng)建小明
p1.eat()
可以將子類型的對象賦值給父類型的變量(因為子類跟父類之間是IS-A關(guān)系)
學(xué)生是人, 老師是人, 所以學(xué)生和老師的對象可以賦值給人類型的變量
let student: Person = Student(name: "張三", age: 18, gender: .Female, major: "計算機科學(xué)與技術(shù)")//創(chuàng)建學(xué)生張三
student.eat()//繼承父類吃飯的方法
如果要將父類型的變量轉(zhuǎn)換成子類型需要用as運算符進(jìn)行類型轉(zhuǎn)換
如果能夠確認(rèn)父類型的變量中就是某種子類型的對象可以用as!進(jìn)行轉(zhuǎn)換
如果不確定父類型的變量中是哪種子類型可以用as?嘗試轉(zhuǎn)換
(p2 as! Student).study("Swift程序設(shè)計")
if let temp = p2 as? Teacher {
temp.teach("Java")
}
else {
print("\\(p2.name)不是老師!!!")
}
面向?qū)ο?/h3>
終極原則: 高內(nèi)聚, 低耦合
面向?qū)ο笃咴瓌t:
- 單一職責(zé)原則(SRP)
- 開閉原則(OCP)
- 依賴倒轉(zhuǎn)原則(面向抽象編程, DIP)
- 里氏替換原則(LSP) - 能用父類型的地方就一定可以使用子類型
- 接口隔離原則(ISP)
- 合成聚合復(fù)用原則(CARP)
- 迪米特法則(LoD
GoF設(shè)計模式 - 23種設(shè)計模式
多態(tài)
同樣的對象類型(Pet類型)接收相同的消息(調(diào)用相同的方法)
但是做了不同的事情 這就是多態(tài)(polymorphism)
實現(xiàn)多態(tài)的關(guān)鍵步驟:
1.方法重寫(子類在繼承父類的過程中對父類已有的方法進(jìn)行重寫, 而且不同的子類給出各自不同的實現(xiàn)版本)
2.對象造型(將子類對象當(dāng)成父類型來使用)
可以通過if+as?將父類型安全的轉(zhuǎn)換成子類型然后再調(diào)用子類特有方法
例 首先創(chuàng)建動物父類
class Pet {
var nickname: String
var gender: Gender
var age: Int
init(nickname: String, gender: Gender, age: Int) {
self.nickname = nickname
self.gender = gender
self.age = age
}
func play() {
print("\\(nickname)正在玩耍.")
}
func shout() {
print("\\(nickname)發(fā)出了叫聲.")
}
}
創(chuàng)建子類 貓
// Cat和Pet之間是IS-A關(guān)系(繼承)
class Cat: Pet {
var hairColor: String?
// 父類有的方法子類可以重新實現(xiàn) 這個過程叫方法重寫
// 需要在方法前添加override關(guān)鍵字
// 重寫有時也被稱為置換/覆蓋/覆寫
override func play() {
print("\\(nickname)正在玩毛線球.")
}
override func shout() {
print("\\(nickname): 喵喵喵……")
}
}
創(chuàng)建子類 狗
class Dog: Pet {//繼承動物類
init(nickname: String, gender: Gender, age: Int) {
super.init(nickname: nickname, gender: gender, age: age)
}
override func play() {//重寫玩耍的方法
print("\\(nickname)正在接飛碟.")
}
override func shout() {//重寫叫的方法
print("\\(nickname): 旺旺旺……")
}
}
創(chuàng)建 貓哮兰,狗
let petsArray = [
Cat(nickname: "加菲", gender: .Female, age: 2),
Dog(nickname: "旺財", gender: .Male, age: 3, )
]
for pet in petsArray {
pet.eat()
pet.play()
}
運行結(jié)果: