Swift第二周学习总结

Swift-杨夏

第六天

集合

1.集合的定义

var a: Set<Int> = [1, 2, 3, 1, 2, 5]
var b: Set<Int> = [3, 5, 7, 9, 11]

2.集合的相关应用

a.insert(100)           // 添加元素
a.remove(2)             // 删除元素

print(a.intersect(b))   // 交集(a和b都有的元素)
print(a.union(b))       // 并集(a和b的所有元素)
print(a.subtract(b))    // 差集(a有b没有的元素)

print(a == b)
print(b.isSubsetOf(a))

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))  // 判断两个集合是否相交

字典

1.字典的定义

var dict: [String: String] = ["abacus": "算盘", "abnormal": "异常的", "hello" : "你好", "good": "好的"]

注意:
字典(存放键值对组合的容器)
字典中的每个元素都是由两部分构成的, 冒号前面是键冒号后面是值(key ---> value)
通过键获取对应的值(可空类型, 因为给的键有可能没有与之对应的值)

2.字典的相关应用

// 添加元素
dict["shit"] = "狗屎"
dict["delicious"] = "好吃的"
print(dict)
// 删除元素
// dict.removeValueForKey("hello")
dict["hello"] = nil
print(dict)
print(dict["hello"])
// 修改元素
dict["shit"] = "牛粪"
print(dict)
// 遍历字典中所有的值
for value in dict.values {
    print(value)
}
// 遍历字典中所有的键
for key in dict.keys {
    print("\(key) ---> \(dict[key])")
}
// 直接通过一个元组获得字典中的键和值(原始类型)
for (key, value) in dict {
    print("\(key) ---> \(value)")
}

函数

1.定义函数

func 函数名(参数列表) -> 返回类型 { 函数的执行体 }
Swift中函数的参数可以设定默认值
如果调用函数的时候没有给该参数赋值就直接使用默认值

2.调用函数

函数名(参数值)

3.注意事项


函数的参数名
函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)
如果不写外部参数名那么内部参数名也是外部参数名
可以使用_来作为外部参数名表示省略外部参数名
调用函数的时候要写函数的外部参数名
func myMin(a x: Int, b y: Int) -> Int {
    return x < y ? x : y
}
print(myMin(a: 3, b: 5))

Swift中函数的参数可以设定默认值
如果调用函数的时候没有给该参数赋值就直接使用默认值
如果函数的返回类型不是Void 那么函数中一定有return语句
func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {
    if alreadyGreeted {
        return "怎么又是你, " + personName + "!"
    }
    else {
        return "你好, " + personName + "!"
    }
}
// 调用Swift的函数时, 在默认情况下从第二个参数开始需要写参数名
print(sayHello("王大锤", alreadyGreeted: true))
// 如果没有给第二个参数赋值那么就直接使用默认值false
let str = sayHello("Jack")
print(str)

Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
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))

可以使用元组(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("数组中没有元素!!!")
}

inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
inout类型的参数前要加上&符号
func swap(inout a: Int, inout _ b: Int) -> Void {
    //(a, b) = (b, a)
    let temp = a
    a = b
    b = temp
}

var a = 300, b = 500
swap(&a, &b)  //inout类型的参数前要加上&符号
print("a = \(a)")
print("b = \(b)")

第七天

函数(续)


在Swift中函数是一种类型
这也就意味着函数可以作为变量或常量的类型
同理函数也可以作为另一个函数的参数或返回值
import Foundation
///设计函数foo()求一个数组中所有元素的和
func sum(a: Int, _ b: Int) -> Int {
    return a + b
}
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
}
let a = [1, 2, 3, 4, 5]

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


如果函数的最后一个参数是闭包可以写成尾随闭包的形式
也就是将闭包放到函数参数的圆括号外面写在一对花括号中
如果函数后面有尾随闭包且函数的圆括号中没有参数
那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
var array = ["game", "abacus", "hello", "cat", "good", "internationalization", "chaos", "dislike", "zealot", "young"]

// array.sortInPlace(>) = array.sortInPlace({ $0 > $1 })
// array.sortInPlace() { $0 > $1 }
// array.sortInPlace { $0 > $1 }
array.sortInPlace {
    if $0.characters.count == $1.characters.count {
        return $0 < $1
    }
    return $0.characters.count < $1.characters.count
}
print(array)

数组的补充

  1. 过滤(filter)
  2. 映射(map)
  3. 缩减(reduce)
let array = [23, 37, 96, 55, 40, 92, 68, 88]
// 1. 过滤
let newArray1 = array.filter { $0 > 50 }
print(newArray1)
let newArray2 = array.filter { $0 % 2 == 0 }
print(newArray2)
// 2. 映射
let newArray3 = array.map { $0 * $0 }
print(newArray3)
let newArray4 = array.map { sqrt(Double($0)) }
print(newArray4)
// 3. 缩减
let result1 = array.reduce(0, combine: +)
print(result1)
let result2 = array.reduce(1, combine: *)
print(result2)
let result3 = array.reduce(array[0]) {
    $1 > $0 ? $1 : $0
}
print(result3)
let strArray = ["I", "love", "you"]
let result4 = strArray.reduce("") { $0 + " " + $1 }
print(result4)

步骤1: 定义类(如果你要用的类苹果已经提供了就直接进入第2步)
定义类就可以创建出新的类型
步骤2: 创建对象(调用初始化方法)
步骤3: 给对象发消息(通过给对象发消息来解决问题)
 //定义学生类
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: "骆昊", age: 35)
// 步骤3: 给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("Swift程序设计")
stu1.watchJapaneseAV()

第八天

类 -- 计算属性(computational property)

通常获得某个计算出的值的方法都可以设计成计算属性
计算属性(通过对存储属性做运算得到的属性)
// 0. 发现类
//  - 在对问题的描述中找名词和动词
//  - 名词会成为类或者类中的属性 动词会成为类中的方法

// 1. 定义类
//  - 数据抽象(属性)
//  - 行为抽象(方法)
//  - 初始化方法

// 访问修饰符
//  - public (公开)
//  - internal (内部的) - 默认
//  - private (私有)
class Circle {
    // stored property
    // 存储属性(保存和圆相关的数据的属性)
    var center: Point
    var radius: Double
    
    init(center: Point, radius: Double) {
        self.center = center
        self.radius = radius
    }
    // 通过计算属性返回圆的周长
    var perimeter: Double {
        // 圆的周长是一个只读属性
        // 所以此处只有get{}没有set{}
        get { return 2 * M_PI * radius }
    }
    // 通过计算属性返回圆的面积
    var area: Double {
        get { return M_PI * radius * radius }
    }
}

let r = 5.5
// 2. 创建对象
let small = Circle(radius: r)
let big = Circle(radius: r + 3)
// 3. 给对象发消息(调用对象的方法)
let fencePrice = big.perimeter * 1.5
print(NSString(format: "围墙的造价为: ¥%.1f元", fencePrice))
let aislePrice = (big.area - small.area) * 3.5
print(NSString(format: "过道的造价为: ¥%.1f元", aislePrice))

类 -- 便利构造器

我们可以在一个类中定义多个初始化方法:便利初始化方法(便利构造器),
简而言之:调用了其他的初始化方法的初始化方法
import Foundation

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)
    }
    
    func moveTo(x: Double, _ y: Double) {
        self.x = x
        self.y = y
    }
    
    func moveBy(dx: Double, _ dy: Double) {
        x += dx
        y += dy
    }
}

let p1 = Point()
let p2 = Point(x: 3, y: 4)
let p3 = Point(point: (-3.5, 6.7))

print(p1.distanceTo(p2))
print(p2.distanceTo(p3))


类的扩展(extension)

如果在某个特定的应用场景中你发现现有的类缺少了某项功能那么可以通过类扩展(extension)的方式现场添加这项功能
func randomInt(min: UInt32, _ max: UInt32) -> Int {
    return Int(arc4random_uniform(max - min + 1) + min)
}
//在UIColor类中添加一个产生随机色的静态方法
extension UIColor {
    static func randomColor() -> UIColor {
        let r = CGFloat(randomInt(0, 255)) / 255.0
        let g = CGFloat(randomInt(0, 255)) / 255.0
        let b = CGFloat(randomInt(0, 255)) / 255.0
        return UIColor(red: r, green: g, blue: b, alpha: 1)
    }
}

第九天

运算符的重载与级联编程思想

举例:设计一个关于分数的加减乘除
import Foundation

// 短除法(欧几里得算法)
// 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)
}

func /(one: Fraction, two: Fraction) -> Fraction {
    return one.div(two)
}
let f1 = Fraction(num: 3, den: -4)
let f2 = Fraction(num: 8, den: 9)

print(f1.info)
print(f2.info)

let f3 = f1 + f2
print(f3.info)
let f4 = f1 - f2
print(f4.info)
let f5 = f1 * f2
print(f5.info)
let f6 = f1 / f2
print(f6.info)

注释的规范化书写

import Foundation

// 存储属性通常是private的 因为数据要保护起来
// 方法一般是public的 因为方法是对象接受的消息
// 如果自定义的类没有打算在其他项目中使用 可以不写访问修饰符
// 直接使用默认的internal修饰符表示在本项目中公开对其他项目私有

/// 学生
public class Student {
    private var _name: String
    private var _age: Int
    
    /// 学生姓名隐去最后一个字符
    public var name: String {
        get {
            let displayName = _name.substringToIndex(_name.endIndex.advancedBy(-1))
            return displayName + "*"
        }
    }
    
    /// 学生的年龄
    public var age: Int {
        get { return _age }
    }
    
    /**
     初始化方法
     - parameter name: 姓名
     - parameter age:  年龄
     */
    public init(name: String, age: Int) {
        _name = name
        _age = age
    }
    
    /**
     吃饭
     - parameter food: 吃的东西
     */
    public func eat(food: String) {
        print("\(_name)正在吃饭.")
    }
    
    
    /**
     学习
     - parameter courseName: 课程的名称
     - parameter hour: 学习时间
     - returns: 学会了返回true否则返回false
     */
    public func study(courseName: String, hour: Int) -> Bool {
        print("\(_name)正在学习\(courseName).")
        return hour > 180 ? true : false
    }
    
    /**
     看片
     */
    public func watchJapaneseAV() {
        if _age >= 18 {
            print("\(_name)正在观看爱情动作片.")
        }
    }
}

以上代码的规范化注释效果截图如下:

屏幕快照 2016-08-12 下午4.14.05.png
屏幕快照 2016-08-12 下午4.14.05.png

第十天

继承

继承: 从已有的类创建新类的过程
提供继承信息的称为父类(超类/基类)
得到继承信息的称为子类(派生类/衍生类)
通常子类除了得到父类的继承信息还会增加一些自己特有的东西
所以子类的能力一定比父类更强大
继承的意义在于子类可以复用父类的代码并且增强系统现有的功能

注意:

1.可以将子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
例如:学生是人, 老师是人, 所以学生和老师的对象可以赋值给人类型的变量

2.如果要将父类型的变量转换成子类型需要用as运算符进行类型转换
如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
如果不确定父类型的变量中是哪种子类型可以用as?尝试转换(可以通过if+as?将父类型安全的转换成子类型然后再调用子类特有方法)

多态

同样的对象类型(Pet类型)接收相同的消息(调用相同的方法)
但是做了不同的事情 这就是多态(polymorphism)

实现多态的关键步骤:
1. 方法重写(子类在继承父类的过程中对父类已有的方法进行重写, 而且不同的子类给出各自不同的实现版本)
2. 对象造型(将子类对象当成父类型来使用)

重写(override)

父类有的方法子类可以重新实现 这个过程叫方法重写
需要在方法前添加override关键字
重写有时也被称为置换/覆盖/覆写

面向对象那些事


编程的终极原则: 高内聚, 低耦合
面向对象七原则:

  1. 单一职责原则(SRP) - 每一个类应该专注于做一件事情
  2. 开闭原则(OCP) - 面向扩展开放,面向修改关闭
  3. 依赖倒转原则(面向抽象编程, DIP) - 定义方法参数类型的时候尽可能使用父类型(抽象类型),因为如果用父类型的参数调用方法时可以传入任意子类型对象
  4. 里氏替换原则(LSP) - 能用父类型的地方就一定可以使用子类型
  5. 接口隔离原则(ISP) - 应当为客户端提供尽可能小的单独的接口,而不是提供大
    的总的接口
  6. 合成聚合复用原则(CARP) - 尽量使用合成/聚合达到复用,尽量少用继承。原则:
    一个类中有另一个类的对象
  7. 迪米特法则(LoD) - 又叫最少知识原则,一个软件实体应当尽可能少的与其
    他实体发生相互作用

GoF设计模式 - 23种设计模式


古人的思想

爱人, 待周爱人而后为爱人
---《墨子·取周》

白马, 马也, 乘白马, 乘马也
黑马, 马也, 乘黑马, 乘马也
娣, 美人也, 爱娣非爱美人也
盗, 人也, 恶盗非恶人也
---《墨子·小取》

代码示例:

import Foundation

class Employee {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    var salary: Double {
        get { return 0 }
    }
}

class Manager: Employee {
    
    override var salary: Double {
        get { return 12000 }
    }
}

class Programmer: Employee {
    var workingHour = 0
    
    override var salary: Double {
        get { return 200 * Double(workingHour) }
    }
}

class Salesman: Employee {
    var sales = 0.0
    
    override var salary: Double {
        get { return 1000 + sales * 0.05 }
    }
}


let empsArray = [
    Manager(name: "王大锤"),
    Programmer(name: "骆昊"),
    Programmer(name: "余婷"),
    Salesman(name: "广告莎"),
    Salesman(name: "欧阳坚"),
    Programmer(name: "周鸿祎")
]

for emp in empsArray {
    if let worker = emp as? Programmer {
        print("请输入\(worker.name)本月工作时间: ", terminator: "")
        worker.workingHour = inputInt()
    }
    else if let worker = emp as? Salesman {
        print("请输入\(worker.name)本月销售额: ", terminator: "")
        worker.sales = inputDouble()
    }
    // 员工工资的计算属性是重写过的多态行为
    print("\(emp.name)本月工资为: ¥\(emp.salary)元")
}

--更多精彩内容请关注:Youth丶夏夏--

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

推荐阅读更多精彩内容