Swift第二周学习总结

Swift.jpg

一. 字典(Dictionary)与集合(Set)

1. 字典 -- 存放键值对组合的容器

Dictionary.png
  • 字典中的每个元素都是由两部分构成的, 冒号前面是键,冒号后面是值
var myDict: [String: String] = ["第一个键": "第一个值", "Hello": "你好"]
  • 通过键获取对应的值(可空类型, 因为给的键有可能没有与之对应的值)
    key --> value
print(myDict["Hello"]!) 
print(myDict["abc"])
// 你好
// nil
  • 对于数组的简单操作
myDict["谢谢"] = "不用谢"        // 添加元素
myDict.removeValueForKey("字典里的第一个键")  // 删除元素(myDict["字典里的第一个键"] = nil 同意可以达到删除的效果)
myDict["Hello"] = "world"      // 修改元素
// 遍历字典中所有的键
for key in myDict.keys {
    print("\(key) --> \(dict[key])")
}
// 直接通过一个元组获得字典中的键和值(原始类型)
for (key, value) in myDict {
    print("\(key) ---> \(value)")
}

1. 集合 -- 存放键值对组合的容器

Set.png
  • 对于集合的简单操作
var a: Set<Int> = [1, 2, 3, 1, 2, 4]
myArray.insert(100)           // 添加元素 
// 1, 2, 3, 4, 100
myArray.remove(2)             // 删除元素
// 1, 3, 4, 100
let b: Set<Int> = [3, 4, 7, 9]
print(a.intersect(b))   // 交集(a和b都有的元素)  
// 3, 4
print(a.union(b))       // 并集(a和b的所有元素)
// 1, 3, 4, 100, 7, 9
print(a.subtract(b))    // 差集(a有b没有的元素)
// 1, 2, 100
let c: Set<Int> = [1, 3]
print(c.isSubsetOf(a))      // 判断c是不是a的子集
// true
print(a.isSupersetOf(c))    // 判断a是不是c的超集
// true
print(a.isDisjointWith(b))  // 判断两个集合是否相交
// true

二. 函数(Function)

1. 函数的参数名

函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)
(1)如果不写外部参数名那么内部参数名也是外部参数名
(2)可以使用_来作为外部参数名表示省略外部参数名

func myMin(a x: Int, b y: Int) -> Int {
         return x < y ? x : y
}
// 调用函数的时候要写函数的外部参数名
print(myMin(a: 3, b: 5))

2. 定义函数

func 函数名(参数列表) -> 返回类型 { 函数的执行体 }
(1) Swift中函数的参数可以设定默认值
(2) 如果调用函数的时候没有给该参数赋值就直接使用默认值
(3) 如果函数的返回类型不是Void 那么函数中一定有return语句

func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {
    if alreadyGreeted {
        return "怎么又是你, " + personName + "!"
    }
    else {
        return "你好, " + personName + "!"
    }
}

3. 调用函数

(1)函数名(参数值)
(2)调用Swift函数时, 在默认情况下从第二个参数开始需要写参数名
(3)如果没有给第二个参数赋值那么就直接使用默认值false

let str = sayHello("Jack")
print(str)
//  你好, Jack!

(4)Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)

func sum(nums: Int...) -> Int {
    var total = 0
    for num in nums {
        total += num
    }
    return total
}
print(sum())           // 0
print(sum(999))        // 999
print(sum(1, 2, 3))    // 6

(5) 可以使用元组(tuple)让函数一次返回多条数据

// 返回最小值和最大值的函数
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.count == 0 {
        return nil
    }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        }
        else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

if let b = minMax([23, 45, 99, 68, 72, 12, 55]) {
    print(b.min)        // print(b.0)
    print(b.max)        // print(b.1)
}
else {
    print("数组中没有元素!!!")
}
// 12  99

(6)inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
(7)inout类型的参数前要加上&符号

func swap(inout a: Int, inout _ b: Int) -> Void {
    (a, b) = (b, a)
}

var a = 300, b = 500
swap(&a, &b)
print("a = \(a)")   // a = 500
print("b = \(b)")   // b = 300

(8) 函数调用传参都是传值

4. 函数也是一种类型

(1) 在Swift中函数是一种类型
(2) 这也就意味着函数可以作为变量或常量的类型
(3) 同理函数也可以作为另一个函数的参数或返回值

// 定义一个求和函数 sum()
func sum(a: Int, _ b: Int) -> Int {
    return a + b
}
// 定义一个以函数为参数的foo()函数
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
}
// 数组a
let a = [1, 2, 3, 4, 5]

// 当调用foo函数时第二个参数可以传什么?
// 1. 所有自定义的(Int, Int) -> Int类型的函数
print(foo(a, fn: sum))               // 15
// 2. 传入已有的二元运算符: + - * / %(因为运算符也是函数)
print(foo(a, fn: +))                 // 15
// 3. 传入匿名函数(闭包)
// 3.1 完整的闭包写法
print(foo(a, fn: { (a, b) -> Int in
    return a + b
}))                                  // 15
// 3.2 省略掉类型和不必要的括号
print(foo(a, fn: { a, b in a + b })) // 15
// 3.3 省略参数名
print(foo(a, fn: { $0 + $1 }))       // 15
// 3.4 尾随闭包
print(foo(a) { (a, b) -> Int in
    return a + b
})                                   // 15
print(foo(a) { $0 + $1 })            // 15

(4) 尾随闭包的例子

var array = [1 ,8,99]
// 如果函数的最后一个参数是闭包可以写成尾随闭包的形式
// 也就是将闭包放到函数参数的圆括号外面写在一对花括号中
array.sortInPlace() { $0 > $1 }
print(array) // [99, 8, 1]
// 如果函数后面有尾随闭包且函数的圆括号中没有参数
// 那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
 array.sortInPlace { $0 > $1 }
print(array) // [99, 8, 1]

三. 过滤(Filter),映射(Map)和缩减(Reduce)

  • 过滤(Filter)

let array = [1, 2, 3, 4, 5, 6, 7, 8]
let newArray1 = array.filter { $0 > 5 }
print(newArray1)
// [6, 7 ,8]
let newArray2 = array.filter { $0 % 2 == 0 }
print(newArray2)
// [2, 4, 6, 8]
  • 映射(Map)

let newArray3 = newArray1.map { $0 * $0 }
print(newArray3)
// [36, 49, 64]
let newArray4 = newArray3.map { sqrt(Double($0)) }
print(newArray4)
// [6, 7, 8]
  • 缩减(Reduce)

let result1 = array.reduce(0, combine: +)
print(result1)     // 求和  36
let result2 = array.reduce(1, combine: *)
print(result2)     // 求积  40320
let result3 = array.reduce(array[0]) {
    $1 > $0 ? $1 : $0
}
print(result3)     // 最大值 8
let strArray = ["I", "love", "you"]
let result4 = strArray.reduce("") { $0 + $1+ " " }
print(result4)     // I love you

四. 类(Class)

1. 类的相关修饰

  • 访问修饰符
  • public (公开)
  • internal (内部的) - 默认
  • private (私有)
  • 存储属性(stored property)
    • 保存与数据抽象相关的数据的属性
  • 计算属性(computational property)
    • 通常获得某个计算出的值的方法都可以设计成计算属性
    • 通常有get{}和set{}两种

2. 类的使用

步骤1: 定义类(如果你要用的类苹果已经提供了就直接进入第2步)
步骤2: 创建对象(调用初始化方法)
步骤3: 给对象发消息(通过给对象发消息来解决问题)

 // 步骤1: 定义类(如果你要用的类苹果已经提供了就直接进入第2步)
 // 定义类就可以创建出新的类型
 // 学生类
class Student {
    // 变量定义到类的外面就叫变量 - variable
    // 变量定义到类的里面就叫属性 - property
    // 数据抽象 - 找到和学生相关的属性(找名词)
    var name: String
    var age: Int
    
    // 初始化方法(构造方法/构造器) - constructor
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    // 函数写到类的外面就叫函数 - function
    // 函数写到类的里面就叫方法 - method
    // 行为抽象 - 找到和学生相关的方法(找动词)
    func eat() {
        print("\(name)正在吃饭.")
    }
    
    func study(courseName: String) {
        print("\(name)正在学习\(courseName).")
    }
    
    func watchJapaneseAV() {
        if age >= 18 {
            print("\(name)正在观看岛国爱情动作片.")
        }
        else {
            print("亲爱的\(name), 我们推荐你观看《熊出没》")
        }
    }
}

// 步骤2: 创建对象(调用初始化方法)
let stu1 = Student(name: "Frank", age: 18)
// 步骤3: 给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("Swift程序设计")
stu1.watchJapaneseAV()
// Frank正在吃饭.
// Frank正在学习Swift程序设计.
// Frank正在观看岛国爱情动作片.

let stu2 = Student(name: "狗蛋", age: 2)
stu2.eat()
stu2.study("中国近代史")
stu2.watchJapaneseAV()
// 狗蛋正在吃饭.
// 狗蛋正在学习中国近代史.
// 亲爱的狗蛋, 我们推荐你观看《熊出没》

3. 类的便利初始化方法(Convenience)

// 点类
class Point {
    var x: Double
    var y: Double
    
    // 我们可以在一个类中定义多个初始化方法
    
    // 便利初始化方法 / 便利构造器
    // 调用了其他的初始化方法的初始化方法
    convenience init() {
        self.init(x: 0, y: 0)
    }
    
    convenience init(point: (Double, Double)) {
        self.init(x: point.0, y: point.1)
    }
    
    // 指派初始化方法 / 指派构造器
    // 被其他初始化方法调用的初始化方法
    init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }
    
    // 计算两点间的距离
    func distanceTo(other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return sqrt(dx * dx + dy * dy)
    }
}

3. 运算符的重载(Operrator overloading)

以下以自定义分数类,重载运算符为例:

// 短除法(欧几里得算法)
// x和y的最大公约数跟y%x和x的最大公约数是一样的
// 找到两个数的最大公约数( 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
    }
}

// 自定义分数类
class Fraction {
    private var _num: Int  // 分子
    private var _den: Int  // 分母
    
    // 计算属性 - 获取分数的信息
    var info: String {
        get {
            return _num == 0 || _den == 1 ? "\(_num)" : "\(_num)/\(_den)"
        }
    }
    
    init(num: Int, den: Int) {
        _num = num
        _den = den
        simplify()
        normalize()
    }
    
    // 自定义分数的加,减,乘,除法
    func add(other: Fraction) -> Fraction {
        return Fraction(num: _num * other._den + other._num * _den, den: _den * other._den)
    }
    
    func sub(other: Fraction) -> Fraction {
        return Fraction(num: _num * other._den - other._num * _den, den: _den * other._den)
    }
    
    func mul(other: Fraction) -> Fraction {
        return Fraction(num: _num * other._num, den: _den * other._den)
    }
    
    func div(other: Fraction) -> Fraction {
        return Fraction(num: _num * other._den, den: _den * other._num)
    }
    
    // 标准化正负号
    func normalize() -> Fraction {
        if _den < 0 {
            _num = -_num
            _den = -_den
        }
        return self
    }
    
    // 对分数进行通分
    func simplify() -> Fraction {
        if _num == 0 {
            _den = 1
        }
        else {
            let x = abs(_num)
            let y = abs(_den)
            let g = gcd(x, y)
            _num /= g
            _den /= g
        }
        return self
    }
}

// 运算符重载(为自定义的类型定义运算符)
func +(one: Fraction, two: Fraction) -> Fraction {
    return one.add(two)
}

func -(one: Fraction, two: Fraction) -> Fraction {
    return one.sub(two)
}

func *(one: Fraction, two: Fraction) -> Fraction {
    return one.mul(two)
}

let f1 = Fraction(num: 1, den: -2)
let f2 = Fraction(num: 4, den: 5)

print(f1.info)      // -1/2
print(f2.info)      // 4/5

let f3 = f1 + f2
print(f3.info)      // 3/10
let f4 = f1 - f2
print(f4.info)      // -13/10
let f5 = f1 * f2
print(f5.info)      // -2/5
let f6 = f1 / f2
print(f6.info)      // -5/8

4. 继承(Inheritance)

  • 继承: 从已有的类创建新类的过程
  • 提供继承信息的称为父类(超类/基类)
  • 得到继承信息的称为子类(派生类/衍生类)
  • 通常子类除了得到父类的继承信息还会增加一些自己特有的东西
  • 所以子类的能力一定比父类更强大
  • 继承的意义在于子类可以复用父类的代码并且增强系统现有的功能
  • 子类和父类之间是IS-A关系
// GET: 枚举是定义符号常量的最佳方式
// GET: 符号常量总是优于字面常量
// 性别的枚举
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)正在吃饭.")
    }
}
    // 继承了Person类
class Student: 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) {
        print("\(name)是\(major)专业的学生.")
        print("\(gender == .Male ? "他" : "她")正在学习\(courseName).")
    }
}

5. 多态(Polymorphism)

  • 同样的对象类型接收相同的消息(调用相同的方法)但是做了不同的事情 这就是多态
  • 实现多态的关键步骤:
    (1) 方法重写(override)(子类在继承父类的过程中对父类已有的方法进行重写, 而且不同的子类给出各自不同的实现版本)
    (2) 对象造型(将子类对象当成父类型来使用)
class Pet {
    var nickname: String
    var age: Int
    
    init(nickname: String, age: Int) {
        self.nickname = nickname
        self.age = age
    }
    
    func shout() {
        print("\(nickname)发出了叫声.")
    }
}
    // 子类Cat继承了Pet,Cat和Pet之间是IS-A关系
class Cat: Pet {
    var hairColor: String?

    // 方法重写需要在方法前添加override关键字
    // 重写有时也被称为置换/覆盖/覆写
    override func shout() {
        print("\(nickname): 喵喵喵……")
    }
}

开心幽默最重要,加油!!!

xixi.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容