我的Swift的学习总结 -->第二周

集合

集合:Set,定义一个集合可以写成:var 集合名 : Set<集合类型> = [集合元素],具体的集合应用如下:

    var a : Set<Int> = [1,2,3,4,6,2,4,8,3,1,14]
    print(a)
    //添加、删除元素
    a.insert(435)         //添加元素
    a.remove(2)           //删除元素
    
    print(a)
    //集合遍历
    for x in a {
        print(x)
    }
    
    var b:Set<Int> = [3,5,7,9,11]
    
    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的子集
    print(c.isSupersetOf(a)) // 判断a是不是c的超集
    
    let d:Set<Int> = [5,1000,1351351]
    print(a.isDisjointWith(d)) //判断两个集合是否相交

字典

与数组把相同类型的值存放在一个有序链表里不同,字典是把相同类型的值存放在一个无序集合里

//字典(存放键值对组合的容器)
//字典中的每个元素都是由两部分构成的,冒号前面是键,冒号后面是值

var dict:[String:String] = ["abacus":"算盘","abnormal":"异常的",
"hello":"你好","good":"好的"]
//通过键获取对应的值(可空类型,因为给的键有可能没有与之对应的值)
//key ----> value
print(dict["good"]!)
print(dict["abcdefw"])

//添加元素
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 函数名(参数列表) -> 返回类型 {函数的执行体}
2.Swift中函数的参数可以设定默认值,如果调用函数的时候没有给该参数赋值,就直接使用默认值



func sayHello(personName:String,alreadyGreeted:Bool = false) -> String {
    // let greeting = "Hello," + personName + "!"
    // 如果函数的返回类型不是Void,那么函数中一定有return语句
    // return greeting
    // personName = "***" // 编译错误
    if alreadyGreeted {
        return "怎么又是你," + personName + "~"
    }
    else {
        return "你好," + personName + "!"
    }
    
}

调用函数:
函数名(参数值),调用Swift的函数时,在默认情况下从第二个参数开始需要写参数名

print(sayHello("帝辛", alreadyGreeted: true))
// 如果没有给第二个参数赋值,那么就直接使用默认值false
let str = sayHello("姒癸")
print(str)

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

func sum(a a: Int = 0,b: Int = 0,c: Int  = 0) -> Int {
    return a + b + c
}

print(sum(a: 1,b: 2,c: 3))
print(sum())
print(sum(c: 100))
print(sum(c: 100,a: 200))

// Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
func sum(nums: Int...) -> Int {
    var total = 0
    for num in nums {
        total  += num
    }
    return total
}

print(sum())
print(sum(32))
print(sum(1,2,3,4,2,3,486,48,5))
print(sum(1,23,36))


// 可以使用元组(tuple)让函数一次返回多个结果
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty {
        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([41,12,86,64,31,34,635,13,12,0,2,1]) {
    print(b.min)        //print(b.0)
    print(b.max)        //print(b.1)
}
else {
    print("数组中没有元素")
}


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



var a = 15343 , b = 1553
// 函数调用传参都是传值
swap(&a, &b)
print("a = \(a)")
print("b = \(b)")

//    // inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
//    func createX(inout x: Int) {
//        x = 1000
//    }
//    var x = 1
//    // inout类型的参数前要加上&符号
//    createX(&x)
//    print(x)

//使用switch分支结构
func sayHello(name:String) ->String {
    let date = NSDate()
    let cal = NSCalendar.currentCalendar()
    let hour = cal.component(.Hour, fromDate: date)
    
    let greeting: String
    
    switch hour {
    case 0...5:     // 不同的分支可以有重叠的部分
        greeting = "怎么还没睡呀"
       // fallthrough   //继续执行下一个case(自动执行下一个分支)
    case 3...10:    //匹配了一个分支之后不再匹配其他的分支
        greeting = "早起的鸟儿有虫吃"
    case 11...13:
        greeting = "中午好"
    case 14...18:
        greeting = "下午好"
    default:
        greeting = "晚上好"
    }
    return name + "," + greeting + "!"
}

print(sayHello("wuli小凡"))
// 设计一个函数传入两个整数m和n,计算从m到n的和

func sum(n: Int ,m: Int) -> Int {
    let (a, b) = m > n ? (n, m) : (m, n)
    var s = 0
    for i in a...b {
        s += i
    }
    return s
}
print(sum(5, m: 3))
// 设计一个函数输入三条边的长度判断能不能构成三角形

func side(a:Int,b:Int,c:Int) -> Bool {
    let d = a + b > c && a + c > b && b + c > a ? true : false
    return d
}
print(side(12, b: 14, c: 27))

设计一个函数传入年月日返回该日期是这一年的第几天,下面是设计出的函数

func daysOfYear(year: Int,month: Int,day: Int) ->Int {
    var daysOfMonth = [31,28,31,30,31,30,31,31,30,31,30,31]
    var sum = 0
    if isLeapYear(year) && month > 2 {
        daysOfMonth[1] = 29
    }
    for days in daysOfMonth[0..<month - 1] {
        sum += days
    }
    return sum + day
}
func isLeapYear(year:Int) -> Bool {
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}

print(daysOfYear(2100, month: 9, day: 8))

求阶乘
函数递归调用(一个函数直接或间接的调用自身)
1.递归公式
2.收敛条件

func factorial(n: Int) -> Double {
    if n == 0 || n == 1 {
        return 1
    }
    return Double(n) * f(n - 1)
}

var counter = 1
汉诺伊塔

汉诺伊塔游戏->
游戏目的:将a上的圈移动到b上,且仍然是按照最大的圈在最下面最下的圈在最上面的顺序依次放置。
规则:
1.在移动的过程中一次只能移动一个圈
2.在游戏过程中始终保证小圈在大圈上面

var counter = 1
func hanoi(n: Int, _ a: String, _ b: String, _ c: String) {
    if n > 0 {
        hanoi(n - 1, a, c, b)
        print("\(counter)\(a)--->\(b)")
        counter += 1
        hanoi(n - 1, c, b, a)
    }
}
// 用递归计算1 - n的和
func sum(n: Int) -> Int {
    if n == 1 {
        return 1
    }
    return n + sum(n - 1)
}
// 设计一个函数计算组合数(C(m,n)) = m!/(n!*(m-n)!)

    // 调用上面用递归方式设计出的阶乘函数
    func combine(m: Int,n: Int) -> Int {
        //assert(m >= n,"m必须大于等于n")
        let p = factorial(m)
        let q = factorial(n)
        let r = factorial(m - n)
        let c = p / (q * r)
        
        return Int(c)
    }
    print(combine(5, n: 3))

闭包

闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 匿名函数比较相似。
全局函数和嵌套函数其实就是特殊的闭包。

func sum(a: Int, _ b: Int) -> Int {
    return a + b
}


func mul(a: Int, _ b: Int) -> Int {
    return a * b
}

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

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: Int, b: Int) -> Int in
    return a + b
//    return a * b
//    return a / b
//    return a - b
//    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 = ["hello","game","water","cat","dog","elephant",
"monkey","food","young","fuyuanhui","love"]
// array.sortInPlace() 默认升序
// array.sortInPlace(>)
// array.sortInPlace({ $0 > $1 })
// array.sortInPlace() {$0 > $1}
// array.sortInPlace {$0 > $1}
// 如果函数的最后一个参数是闭包可以写成尾随闭包的形式
// 也就是将闭包放到函数参数的圆括号外面写在一对花括号中
// 如果函数后面有尾随闭包且函数的圆括号中没有参数
// 那么函数多圆括号也可以省略(仅限于有尾随闭包的场景)
    //array.sortInPlace { (one: String, two: String) -> Bool in
    //    return one.characters.count > two.characters.count
    //}
// 可省略成:
array.sortInPlace {
    if $0.characters.count == $1.characters.count {
        return $0 > $1
    }
    return $0.characters.count > $1.characters.count
}
print(array)

数组使用闭包方法进行过滤、映射和缩减:

let array = [23,46,87,5,66,18,53,12,2,48,3,1,42]

// 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 = ["fu","yuan","hui"]
let result4 = strArray.reduce("") { $0 + "" + $1 }
print(result4)

Swift 类是构建代码所用的一种通用且灵活的构造体。我们可以为类定义属性(常量、变量)和方法。
与其他编程语言所不同的是,Swift 并不要求你为自定义类去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类,系统会自动生成面向其它代码的外部接口。
如何定义一个类(过程):

步骤1:定义类(如果你要用的类苹果没有那么就要自己定义了)

如果已经有了就直接进行第二步
定义类就可以创建出新的类型

    // 学生类
    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 watchTV() {
            if age >= 18 {
                print("\(name)正在观看《人与自然》。")
            }
            else {
                print("亲爱的\(name),我们推荐你观看《熊出没》!")
            }
        }
    }

步骤2: 创建对象(调用初始化方法)

    let stu1 = Student(name: "张三", age: 30)

步骤3: 给对象发消息(通过给对象发消息来解决问题)

    stu1.study("Swift程序设计")
    stu1.eat()
    stu1.watchTV()

    let stu2 = Student(name: "小二", age: 15)
    stu2.eat()
    stu2.study("数学")
    stu2.watchTV()

例如:定义一个计算时间的类,用于报表:

    class Clock {
        var hour: Int
        var minute: Int
        var second: Int
        
        init() {
            let date = NSDate()
            let cal = NSCalendar.currentCalendar()
            hour = cal.component(.Hour, fromDate: date)
            minute = cal.component(.Minute, fromDate: date)
            second = cal.component(.Second, fromDate: date)
        }
        
        func showTime() -> String {
            return "\(hour):\(minute):\(second)"
        }
        
        func run() {
            second += 1
            if second == 60 {
                second = 0
                minute += 1
                if minute == 60 {
                    minute = 0
                    hour += 1
                    if hour == 24 {
                        hour = 0
                    }
                }
            }
        }
    }

    let clock = Clock()
    while true {
        print(clock.showTime())
        sleep(1)
        clock.run()
    }

下面是一个小游戏:系统产生一个1-100的随机数让人猜,如果猜大了就提示“大了”,猜小了就提示“小了”,直到猜对了给出提示“游戏结束”。
1⃣️.首先定义一个能产生随机数又能将人猜的数与之进行比较的类:

// 将这个能产生随机数的类称之为机器人(Robot)
class Robot {
    // 数据抽象
    var answer: Int    // 正确答案
    var counter: Int   // 猜的次数
    var hint: String   // 提示信息
    
    // 初始化方法
    // 该保证所有的存储属性都被初始化(有值)
    init() {
        answer = Int(arc4random_uniform(100)) + 1
        counter = 0
        hint = ""
    }
    
    // 行为抽象
    // 判断
    func judge(thyAnswer: Int) -> Bool {
        counter += 1
        if thyAnswer < answer {
            hint = "大一点"
        }
        else if thyAnswer > answer {
            hint = "小一点"
        }
        else {
            hint = "恭喜您猜对了!您一共猜了\(counter)次"
            return true
        }
        return false
    }
    
}

2⃣️.在类以外调用机器人这个类以及类中的方法:

let r = Robot()
var isGameOver = false
repeat {
    print("请输入你猜的数字: ",terminator:"")
    let thyAnswer = inputInt()
    isGameOver = r.judge(thyAnswer)
    print(r.hint)
}while !isGameOver

if r.counter > 7 {
    print("智商☎️!")
}
else if r.counter <= 3 {
    print("神")
}

奥特曼打怪兽

小时候看过的奥特曼打怪兽也可以设计成一个简单的游戏,游戏的设定是一群怪兽一起攻击奥特曼,奥特曼有三种攻击方式:普通攻击、大招、群体魔法伤害,而怪兽只有普通攻击,但是伤害比奥特曼的普通攻击要高。
那么:
1.首先定义奥特曼类

func randomInt(min: UInt32, _ max: UInt32) -> Int {
    return Int(arc4random_uniform(max - min + 1) + min)
}

class Ultraman {
    private var _name: String
    private var _HP: Int
    private var _MP: Int
    
    var isAlive: Bool {
        get {
            return _HP > 0
        }
    }
    
    var name: String {
        get { return _name }
    }
    
    var HP: Int {
        get { return _HP }
        set { _HP = newValue > 0 ? newValue : 0 }
    }
    
    var MP: Int {
        get { return _MP }
    }
    
    init(name: String,HP: Int,MP: Int) {
        _name = name
        _HP = HP
        _MP = MP
    }
    
    func attack(monster: Monster) {
        let injury = randomInt(1740, 3605)
        monster.HP -= injury
        _MP = _MP + 50 > 13000 ? 13000 : _MP + 50
    }
    
//    func hugeAttack(monster: Monster) {
//        let ap  = randomInt(21350, 35481)
//        monster.HP -= ap
//        _MP -= 1250
//    }
    
    func hugeAttack(monster: Monster) {
        let injury = 
        monster.HP * 3 / 4 >= 500000 ? monster.HP * 3 / 4 : 500000
        monster.HP -= injury
        
    }
    
//    func magicalAttack(monsters: [Monster]) {
//        let AP = randomInt(10000, 15000)
//        for i in monsters {
//            i.HP -= AP
//        }
//        _MP -= 2000
//    }
    
    func magicalAttack(monsters: [Monster]) -> Bool {
        if self.MP >= 4000 {
            for monster in monsters {
                if monster.isAlive {
                    monster.HP -= randomInt(10000, 15000)
                }
            }
            _MP -= 2000
            return true
        }
        return false
    }
    
    
}

2.定义怪兽类

class Monster {
    private var _name: String
    private var _HP: Int
    
    var isAlive: Bool {
        get { return _HP > 0 }
    }
    
    var name: String {
        get {
            return _name
        }
    }
    
    var HP: Int {
        get {
            return _HP
        }
        set {
            _HP = newValue > 0 ? newValue : 0
//            if newValue > 0 {
//                _HP = newValue
//            }
//            else {
//                _HP = 0
//            }
        }
    }
    
    init(name: String,HP: Int) {
        _name = name
        _HP = HP
    }
    
    func attack(ultraman: Ultraman) {
        let injury = randomInt(8813, 16350)
        ultraman.HP -= injury
    }
}


3.创建对象调用这两个类进行游戏

// 奥特曼打怪兽

// 从一群怪兽中挑选一只活着的怪兽
func pickOneMonster(mArray: [Monster]) -> Monster {
    var monster: Monster
    repeat {
        let randomIndex = randomInt(0, UInt32(mArray.count - 1))
        monster = mArray[randomIndex]
    }while !monster.isAlive
    return monster
}

// 判断怪兽是否全部死光
func isAllDead(mArray: [Monster]) -> Bool {
    for monster in mArray {
        if monster.isAlive {
            return false
        }
    }
    return true
}

let u = Ultraman(name: "梦比优斯", HP: 450000, MP: 38000)
let mArray = [
    Monster(name: "宇宙恐龙王杰顿", HP: 180000),
    Monster(name: "加拉雷斯", HP: 49000),
    Monster(name: "雷德王", HP: 68000)
]

//let m = Monster(name: "黑暗炸鸡", HP: 120)
var round = 1
repeat {
    
    let m = pickOneMonster(mArray)
    
    let factor = randomInt(1, 10)
    switch factor {
    case 1...7:
        u.attack(m)
        if m.isAlive {
            m.attack(u)
        }
    case 8...9:
        print("\(u.name)奥特曼使用了宝塔镇河妖技能")
        if u.magicalAttack(mArray) {
            for m in mArray {
                if m.isAlive {
                    m.attack(u)
                }
            }
        }
        else {
            u.attack(m)
            if m.isAlive {
                m.attack(u)
            }
        }
    default:
        print("\(u.name)奥特曼使用了动感十字光波技能")
        u.hugeAttack(m)
    }

    u.attack(m)
    if m.isAlive {
        m.attack(u)
    }

链式编程

在一个类中,有时为了方便而在init初始化的时候调用自身创建的方法以实现简化代码等功能。
比如:
分数的四则运算:

普通方法找最大公约数

func gcd(x: Int, _ y: Int) -> Int {
    var a = x < y ? x : y
    while a > 1 {
        if x % a == 0 && y % a == 0 {
            return a
        }
        a -= 1
    }
    return 1
}

短除法(欧几里德算法)找最大公约数

// x和y的最大公约数跟y%x和x的最大公约数是一样的
// 找到分子和分母的最大公约数用于化简
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
    
    init(num: Int,den: Int) {
        _num = num
        _den = den
        normalize()    // 调用的自身所创建的方法
        simplify()    // 在每个运算方法使用的时候自动调用,就叫做链式编程
    }
    
    var info: String {
        get {
            return _num == 0 || _den == 1 ? "\(_num)" : "\(_num)/\(_den)"
        }
    }
    
    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: other._num * _num, den: _den * other._den)
    }
    
    func divide(other: Fraction) -> Fraction {
        return Fraction(num: _num * other._den , den: _den * other._num)
    }
    
    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 normalize() -> Fraction {
        if _den < 0 {
            _num = -_num
            _den = -_den
        }
        return self
    }
    
    let f = Fraction(num: 3,den: -4)
    let f2 = Fraction(num: -8,den: 9)
    print(f.info)

    let f3 = f.add(f2)
    print(f3.info)

    let f4 = f.sub(f2)
    print(f4.info)

    let f5 = f.mul(f2)
    print(f5.info)

    let f6 = f.divide(f2)
    print(f6.info)

   
}

运算符重载

在上面的分数的运算中将四种运算简化,即运算符重载,可以使得创建的对象调用该方法时更加简便
简化的过程(运算符重载):

// 运算符重载(为自定义的类型定义运算符)

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.divide(two)
}

调用的过程:

let f = Fraction(num: 3,den: -4)
let f2 = Fraction(num: -8,den: 9)
print(f.info)

let f3 = f + f2 + f
print(f3.info)

let f4 = f - f2
print(f4.info)

let f5 = f * f2
print(f5.info)

let f6 = f / f2
print(f6.info)

便利构造器和文档注释

便利构造器就是创建类的时候进行的舒适化方法也叫构造方法或构造器。
文档注释是用于创建对象调用类时产生的代码提示消息,可以让使用者了解到该类的方法和各种属性。

文档注释的基本格式:

/**
名称
parameter:
return:
*/

示例:


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

/// 学生类
public class Student {
    // 变量定义到类的外面就叫变量 - variable
    // 变量定义到类的里面就叫属性 - property
    // 数据抽象 - 找到和学生相关的属性(找名词)
    private var _name: String
    private var _age: Int

    // 初始化方法(构造方法/构造器) - constructor - 创建对象要使用的方法
    
    /**
    初始化方法
    - parameter name: 名字
    - parameter age: 年龄
    */
    
    public init(name: String, age: Int) {
        _name = name
        _age = age
    }
    /**
    姓名隐去最后一个字符
     */
    var name: String {
        get {
            let value = _name.characters.count > 2 ? -2 : -1
            //let displayName = _name.substringToIndex(_name.endIndex
              .predecessor())
            let displayName = _name.substringToIndex(_name.endIndex
            .advancedBy(value))
            return displayName + "*"
        }
    }

    ///学生的年龄
    public var age: Int {
        get {return _age}
    }
    // 函数写到类的外面就叫函数 - function
    // 函数写到类的里面就叫方法 - method
    // 行为抽象 - 找到和学生相关的方法(找动词)
    
    
    /**
    吃饭
    */
    public func eat() {
        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 watchTV() {
        if _age >= 18 {
            print("\(_name)正在观看《人与自然》。")
        }
        else {
            print("亲爱的\(_name),我们推荐你观看《熊出没》!")
        }
    }
}

计算属性

计算属性就是将函数中的方法用属性的形式表示出来。
比如:

    var hasMoreCards: Bool {
        get { return cardsArray.count > 0 }
    }
    
    // 它的原型是:
    func hasMoreCards() -> Bool {
        return return cardsArray.count > 0 ? true : false
    }

下面是一个比较综合的实例用来详细阐述了如何创建一个类,计算属性怎么使用等等问题。这是一个扑克游戏,首先定义一个类产生一张扑克牌,其次定义一个类产生一副牌,再定义一个类生成玩家,最后通过调用这几个类完成游戏。

1.定义一张扑克牌类:

// GET: 枚举是定义符号常量的最佳方式
// GET: 符号常量总是优于字面常量
/**
    花色的枚举

- Spade:   黑桃♠️
- Heart:   红心♥️
- Club:    梅花♣️
- Diamond: 方块♦️
*/

enum Suite: String {
    //case Spade = "♠️",Heart = "♥️",Club = "♣️",Diamond = "♦️"
    case Spade = "♠️"
    case Heart = "♥️"
    case Club = "♣️"
    case Diamond = "♦️"
}

/// 一张牌
class Card {
    var suite: Suite
    var face: Int
    
    /**
     初始化方法
     - parameter suite: 花色
     - parameter face:  点数
     */
    init(suite: Suite,face: Int) {
        self.suite = suite
        self.face = face
    }
    /// 牌的信息
    var info: String {
        get {
            var str = suite.rawValue
            switch face {
            case 1: str += "A"
            case 11: str += "J"
            case 12: str += "Q"
            case 13: str += "K"
            default:
                str += "\(face)"
            }
            return str
        }
    }
    
}

2.定义一副扑克牌类:

func randomInt(min: UInt32,max: UInt32) -> Int {
    return Int(arc4random_uniform(max - min + 1) + min)
}

/// 一副牌
class Poker {
    var cardsArray: [Card] = []
    
    init() {
        
        reset()
    }
    
    /**
     重置所有的牌
     */
    func reset() {
        
        cardsArray.removeAll()
        let suitesArray = [Suite.Spade, .Heart, .Club, .Diamond]
        for suite in suitesArray {
            for face in 1...13 {
                let card = Card(suite: suite, face: face)
                cardsArray.append(card)
            }
        }
    }
    
    /**
     洗牌
     */
    func shuffle() {
        // 洗牌之前先重置所有的牌
        reset()
        // 通过随机乱序的方式打乱牌的位置
        for i in 0..<cardsArray.count {
            let j = randomInt(0, max: UInt32(cardsArray.count - 1))
            (cardsArray[i],cardsArray[j]) = (cardsArray[j],cardsArray[i])
        }
    }
    
    /**
     发牌
     - returns: 当前剩下牌中的第一张牌或nil
     */
    func deal() -> Card? {
        if hasMoreCards {
            return cardsArray.removeLast()
        }
        return nil
    }
    
    /// 判断还有没有更多的牌?
    var hasMoreCards: Bool {
        get { return cardsArray.count > 0 }
    }
    
//    func hasMoreCards() -> Bool {
//        return cardsArray.count > 0 ? true : false
//    }
}

3.定义玩家类:

func <(one: Card,two: Card) -> Bool {
    return one.face < two.face
}

class Player {
    var nickname: String
    var cardsOnHand: [Card] = []
    
    init(nickname: String) {
        self.nickname = nickname
    }
    // 玩家获得牌的行为
    func getOneCard(card: Card) {
        cardsOnHand.append(card)
    }
    // 玩家给手里的牌排序的方法
    func sortCards() {
        cardsOnHand.sortInPlace(<)
    }
    
}

4.通过创建对象调用类中的方法来使用这副牌,从而达到游戏目的:

func showPlayerCards(player: Player) {
    print("\(player.nickname)",terminator:":")
    player.sortCards()
    for card in player.cardsOnHand {
        print(card.info,terminator:" ")
    }
    print("")
}

// 创建对象调用类生成游戏
let p = Poker()
p.shuffle()

let playersArray = [
    Player(nickname: "张三"),
    Player(nickname: "李四"),
//    Player(nickname: "王二"),
//    Player(nickname: "大锤")
]

//while p.hasMoreCards {
//    for player in playersArray {
//        if p.hasMoreCards {
//            player.getOneCard(p.deal()!)
//        }
//    }
//}

for _ in 1...2 {
    for player in playersArray {
        if p.hasMoreCards {
            player.getOneCard(p.deal()!)
        }
    }
}

for player in playersArray {
    showPlayerCards(player)
}

到这里一个扑克游戏就产生了!

类扩展

类的扩展:在已有的类的现有功能不能满足使用需求的时候,通过扩展类的功能从而达到从新利用的目的。
比如:扩展系统自带的类: 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)
    }
    
}

系统自带的UIColor类没有随机颜色的产生方法,我们可以通过扩展该类的功能,添加随机颜色的方法以达到这样的效果,这样我们在再次调用UIColor的时候,就可以使用随机颜色的方法了。

继承

继承我们可以理解为一个类获取了另外一个类的方法和属性。当一个类继承其它类时,继承类叫子类,被继承类叫父类(或超类、基类)在 Swift 中,类可以调用和访问父类的方法和属性,并且可以重写它们。
例如:我们可以定义一个类->人,再定义两个类分别是学生和老师,学生和老师都是人,因此可以通过继承人这个类,复用父类的代码增强系统现有功能。

1.父类:人

// 枚举性别
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) 正在吃饭")
    }
    
}

2.子类:老师、学生

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

老师类

class Teacher: Person {

    var title: String
    
    init(name: String,age: Int,gender: Gender,title: String) {
        self.title = title
        super.init(name: name, age: age, gender: gender)
    }
    
    
    func teach(courseName: String) {
        print("\(name)正在教学生\(courseName)")
    }
}

学生类

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 ? "他" : "她")\(name)正在学习\(courseName)")
    }
    
    
    
}

3.创建对象调用类

let p1 = Person(name: "大铁锤", age: 35, gender: .Male)
p1.eat()

// 我们可以将子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
// 学生是人,老师也是人,所以学生和老师的对象可以赋值给人类型的变量
let p2: Person = Student(name: "高渐离", age: 29, gender: .Male, 
        major: "🎵击筑")
p2.eat()

// 如果要将父类型的变量转换成子类型需要用as运算符进行类型转换
// 如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
// 如果不确定父类型的变量中是哪种子类型可以用as?尝试转换
(p2 as! Student).study("弹琴")
if let temp = p2 as? Teacher {
    temp.teach("IOS")
}
else {
    print("\(p2.name)不是老师!")
}

let p3 = Teacher(name: "雪女", age: 28, gender: .Female, title: "舞蹈")
p3.teach("民族舞")

多态

多态可以简单的理解为同样的对象类型接收相同的消息(调用了相同的方法),但是做了不同的事情(结果不一样)。
实现多态的步骤主要有两点:
1.方法重写(子类在继承父类的过程中对父类已有的方法进行重写,而且不同的子类给出各自不同的实现版本)
2.对象造型(将子类对象当成父类型来使用)
具体如下代码:

// 定义父类和父类中的方法及属性
enum Gender {
    case Male
    case Female
}
// 定义宠物类
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 eat() {
        print("\(nickname)正在吃东西.")
    }
    
    func play() {
        print("\(nickname)正在玩耍.")
    }
    
    func shout() {
        print("\(nickname)发出了叫声.")
    }
    
}

// 定义不同的子类及其特有的属性,重写父类已有的方法

// 定义第一种宠物:猫
// Cat和Pet是IS-A关系
class Cat: Pet {
    var hairColor: String?
    
//    init(nickname: String, gender: Gender, age: Int , 
           hairColor: String) {
//        self.hairColor = hairColor
//        super.init(nickname: nickname, gender: gender, age: age)
//    }
    
    override func play() {
        super.play()
        print("\(nickname)正在玩毛线球.")
    }
    
    // 父类有的方法子类可以重新实现 这个过程叫方法重写
    // 需要在方法前添加override关键字
    // 重写有时也被称为置换/覆盖/覆写
    override func shout() {
        print("\(nickname):  喵喵喵...")
    }
    
    func catchTheMouse() {
        print("\(nickname)正在抓🐭.")
    }
}

// 定义第二种宠物:狗 
class Dog: Pet {
    
    var isLarge: Bool
    var variety: String
    
    init(nickname: String, gender: Gender, age: Int, 
    isLarge: Bool, variety: String) {
        self.isLarge = isLarge
        self.variety = variety
        super.init(nickname: nickname, gender: gender, age: age)
    }
    
    func keepTheDoor() {
        if isLarge {
            print("\(nickname)正在看门...")
        }
        else {
            print("\(nickname)太小了谁也咬不过...请不要让它看门!")
        }
    }
    
    func porter() {
        print("\(nickname)正在看门...")
    }
    
    override func shout() {
        super.shout()
        print("\(nickname)正在狂吠...")
    }
    
    func bite() {
        print("\(nickname)正在咬人...")
    }
    
    override func play() {
        super.play()
        print("\(nickname)正在玩耍球球...")
    }
    
    func mate() {
        print("\(nickname)正在交配中...")
    }
}

// 使用
let petsArray = [
    Cat(nickname:"汤姆", gender: .Female, age: 5),
    Dog(nickname: "旺财", gender: .Male, age: 3, isLarge: true, 
    variety: "斗牛犬"),
    Cat(nickname:"加菲", gender: .Male, age: 4),
    Dog(nickname: "大黄", gender: .Male, age: 3, isLarge: false, 
    variety: "土狗"),
    Monkey(nickname: "六耳", gender: .Male, age: 3000, clever: true) 
]

for pet in petsArray {
//    pet.eat()
//    pet.play()

    // 同样的对象类型(Pet类型)接收相同的消息(调用相同的方法)
    // 但是做了不同的事情 这就是多态(polymorphism)
    // 实现多态的关键步骤:
    // 1.方法重写(子类在继承父类的过程中对父类已有的方法进行重写
    // 而且不同的子类给出各自不同的实现版本)
    // 2.对象造型(将子类对象当成父类型来使用)
    pet.shout()

    // 可以通过if + as?将父类型安全的转换成子类型然后再调用子类特有的方法
    if let dog = pet as? Dog {
        dog.keepTheDoor()
    }
    else if let cat = pet as? Cat {
        cat.catchTheMouse()
    }
    else if let monkey = pet as? Monkey {
        monkey.perform()
    }
}

本周总结

本周学习的内容相对于上一周来说简直是呈几何型增长啊,但是每一个知识点都有着大量的练习,虽然有时候是比较懵,但是只要多多练习就能狗掌握了,在这一周的时间里,我感觉我不仅学习到了Swift的相关语法知识,还让我对于编程有了更大的信心。相比较以前一看到代码就范头疼以及一看到代码就不知道怎么写的窘迫,现如今也大为改观了,也许是许多事看起来很恐怖,但是真正做起来的时候会是另一番效果吧。而且现在写起代码来也比原来更有点感觉了,也知道大致的方向了,希望能够在以后的学习时间里不再懵逼,不再迷茫。

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 然而还是没有忍住,就这样痛心疾首地选来选去选了个一开始没看上眼的。NEXT SI NOW ,SO WHAT !
    Beijing阅读 147评论 2 1
  • 繁花落尽时,帘卷西风起,人比黄花瘦,无处诉衷肠。 深秋的天气寒冷萧瑟,灰暗的天空有种漠然的清冷,林间路径上枯黄的落...
    浮生犹若梦阅读 851评论 22 5
  • 想要写字的情绪往往来得突然而且猛烈,无法预备。同样地,如果不能马上提笔,它也会飞快地消失无踪。 说起来有点可笑,自...
    frejayvaine阅读 394评论 0 0