Swift第二周学习总结

Swift总结

一、字典(dictionary)

1.字典:存放键值对组合的容器。
2.字典中的每个元素都有两部分构成,冒号前面是键冒号后面是值。
var dict: [String: String] = ["abacus": "算盘","abnormal": "异常的"]
3.通过键可以获取对应的值(可空类型,因为给的键有可能没有与之对应的值)
print(dict["hello"]!)
4.对元素的操作
✩添加元素:dict["delicious"] = "好吃的"
✩删除元素:dict.removeValueForKey("hello")或dict["hello"] = nil
✩修改元素:dict["abnormal"] = "牛粪"
✩遍历字典中所有的值:for value in dict.values { print(value) }
✩遍历字典中所有的键:for key in dict.keys { print("\(key) ---> \(dict[key])") }注意结果是这样的:abacus ---> Optional("算盘")dict[key]为可空类型
✩直接通过一个元组获得字典中的键和值(原始类型):for (key, value) in dict { print("\(key) ---> \(value)") }现在结果是这样的:abacus ---> 算盘


二、集合(sets)

1.定义两个集合:var a: Set = [1, 2, 3, 1, 2, 5] var b: Set = [3, 5, 7, 9, 11]集合会去掉重复的元素.
2.添加元素:a.insert(100)
3.删除元素:a.remove(2)
4.交集:a.intersect(b)
5.并集:a.union(b)
6.差集:a.subtract(b)
7.判断b是不是a的子集:b.isSubsetOf(a)
8.判断a是不是c的超集:a.isSupersetOf(c)


三、函数(function)

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

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

2.调用函数
★调用Swift的函数时,在默认情况下从第二个参数开始需要写参数名
print(sayHello("rose"))
3.函数的参数名
函数名(外部参数名 内部参数名: 类型,外部参数名 内部参数名:类型)
★如果不写外部参数名那么内部参数名也是外部参数名,可以使用_来省略外部参数名

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

★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,4))     //结果为10

★可以使用元组让函数一次返回多条数据
下面这个函数参数是一个数组,函数的功能是找出最大值、最小值并用一个元组返回

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1.. currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

let b = minMax([12,45,23,89,156,55,38])
print(b.min)    //print(b.0)
print(b.max)    //print(b.1)

★inout - 输入输出参数(不仅将数据传人函数还要从函数中取出数据)

func createX(inout x: Int) {
    x = 1000
}

var x = 1
//使用inout 要加&
createX(&x)
print(x)

例1.//设计一个函数传入两个整数m和n,计算m到n的和

func figure( m: Int,n: Int) -> Int{
    let (a,b) = m > n ? (n,m) : (m,n)
    var sum = 0
    for i in a...b{
        sum += i
    }
    return sum
}
print(figure(3, n: 50))

4.函数的递归调用(一个函数直接或间接的调用自身)

  • 递归公式
  • 收敛条件

例2.设计一个函数计算组合数C(m,n) = m!/n!/(m-n)!

func combine(m: Int,_ n: Int) -> Int{
    let (a,b) = m > n ? (m,n) : (n,m)
//assert (m >= n ,"m必须大于等于n")  //断言
    let comb = f(a) / f(b) / f((a - b))
    return comb
}

阶乘(使用了递归调用)
func f(n: Int ) -> Int{
    if n == 0 || n == 1{
        return 1
    }
    return n * f(n - 1)
}
print(combine(5, 3))

5.函数也可以作为另一个函数的参数或返回值
例如:

func foo(array: [Int], fn: (Int, Int) -> Int) -> Int {  return Int      }

那么当调用foo函数时第二个参数可以传什么?

  • 所有自定义的(Int, Int) -> Int类型的函数
  • 传入已有的二元运算符: +-*/%(因为运算符也是函数)
  • 传入匿名函数(闭包):
1.完整的闭包写法
print(foo(a, fn: { (a, b) -> Int in
    return a + b
}))
2.省略掉类型和不必要的括号
print(foo(a, fn: { a, b in a + b }))
3.省略参数名
print(foo(a, fn: { $0 + $1 }))
4.尾随闭包
print(foo(a) { (a, b) -> Int in
    return a + b
})
print(foo(a) { $0 + $1 })
  • 尾随闭包:
    1.如果函数的最后一个参数是闭包可以写成尾随闭包的形式,也就是将闭包放到函数参数的圆括号外面写在一对花括号中
    2.如果函数后面有尾随闭包且函数的圆括号中没有参数,那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
var array = ["game","abacus","hello","cat","good","honey","shit","young","xman"]
array.sortInPlace() { $0 > $1}
print(array) 
array.sortInPlace { $0 > $1}
print(array)
//结果一样:["young", "xman", "shit", "honey", "hello", "good", "game", "cat", "abacus"]
★数组(增加三种方法)

let array = [23,56,12,96,85,26,15,45]
1.过滤

let newArray = array.filter { $0 > 50 } //过滤掉小于50的元素
let Array = array.filter { (x: Int) -> Bool in
    return x % 2 == 0} //过滤掉奇数,剩下偶数

2.映射

let newArray2 = array.map { (x: Int) -> Int in
    return x * x // {$0 * $0}
}

3.缩减

let newArray3 = array.reduce(0, combine: +)
// 数组各元素相加,初始值为0
let newArray4 = array.reduce(1, combine: *)
//数组各元素相乘,初始值为1
let newArray5 = array.reduce(array[0]) {$1 > $0 ? $1 : $0 }
//找出数组里面最大的数

四、类(class)

1.如何创建一个类,和怎么调用类的方法?

我们创建一个Student类来说明:

  • 定义类

  • 数据抽象(属性)

    • 存储属性(保存相关的数据的属性)
    • 计算属性(通过对储存属性做运算得到的属性)
  • 行为抽象(方法)

  • 初始化方法(我们可以在一个类中定义多个初始化方法)

    • 指派初始化方法/指派构造器(被其他初始化方法调用的初始化方法)
    • 便利初始化方法/便利构造器(调用了其它初始化方法的初始化方法)
  • 访问修饰符

  • public(公开)

  • internal(内部的) - 默认

  • private(私有)

  • 步骤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).")
    }
  • 步骤2: 创建对象(调用初始化方法)
let stu1 = Student(name: "王钢蛋", age: 21)
  • 步骤3: 给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("Swift程序设计")

例3.用面向对象的方式写猜数字游戏
首先建一个机器人的类

class Robot{
    var answer: Int //正确答案
    var counter: Int = 0 //猜的次数
    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
    }
}

然后创建对象,面向对象编程

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("智商感人!")
}
2.类的扩展
  • 如果在某个特定的应用场景中你发现你的类缺少了某项功能
  • 那么可以通过扩展(extension)的方式现场添加这项功能
extension Point{
    var cgPoint: CGPoint{
        get{return CGPointMake(CGFloat(X), CGFloat(Y))}
    }
}
//用Double类型的点(X,Y),构造CGFloat类型的点
3.级联编程和重载函数

例4.计算分数(化简和正规化)

//找最大公约数
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的,因为数据要保护起来
 //方法一般是public的,因为方法是对象接受的消息
 //如果自定义的类没有打算在其他项目中使用,可以不写访问修饰符
 //直接使用默认的internal修饰符表示在本项目中公开对其他项目私有
    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).simplify().normalIze()//级联编程
          }
    func sub(other: Fraction) -> Fraction{
        return Fraction(num: _num * other._den - other._num * _den, den: _den * other._den).simplify().normalIze()
    }
    func mul(other: Fraction) -> Fraction{
        return Fraction(num: _num * other._num, den: _den * other._den).simplify().normalIze()
}
    func div(other:Fraction) -> Fraction{
        return Fraction(num: _num * other._den, den: _den * other._num).simplify().normalIze()
    }
    //正规化
    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)
}
//用+号重新定义加法(add)运算
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)
}
4.继承和多态

1.继承

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

我们先建一个Pet的类(父类)

//枚举类型
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.age = age
        self.gender = gender
        self.nickname = nickname
    }
    func play() {
        print("\(nickname)正在玩.")
    }
    
    func eat(){
        print("\(nickname)正在吃东西.")
    }
    
    func shout(){
        print("\(nickname)发出了叫声.")
    }

再建一个Dog和Cat的类(Pet的子类)

class Dog: Pet {
    var isLarge: Bool
    
    init(nickname: String, gender: Gender, age: Int, isLarge: Bool) {
       self.isLarge = isLarge
        super.init(nickname: nickname, gender: gender, age: age)
    }
    func watchDoor(){
        if isLarge{
           print("\(nickname)正在看门.")
        }else{
            print("\(nickname)太小了,谁也打不过")
        }
    }
    override func shout() {
        print("\(nickname):汪汪汪...")
    }
    override func play() {
        super.play()
        print("\(nickname)正在玩球.")
    }
}
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关键字
    //重写有时也被称为置换/覆盖/覆写
    override func play() {
        super.play()
        print("\(nickname)正在玩毛线球.")
    }
    override func shout() {
        print("\(nickname):喵喵喵...")
    }
    func catchTheMouse(){
        print("\(nickname)正在抓老鼠.")
    }
}
  • 创建对象
let petsArray = [
    Cat(nickname: "加菲", gender: .Female, age: 6, hairColor: "gray"),
    Dog(nickname: "旺财", gender: .Male, age: 10, isLarge: true),
    Dog(nickname: "大黄", gender: .Male, age: 9, isLarge: false)
    ]

2.多态

for pet in petsArray{
    //同样的对象类型(Pet类型)接收相同的消息(调用相同的方法)
    //但是做了不同的事情,这就是多态(polymorphism)
    //实现多态的关键步骤:
    //1.方法重写(子类在继承父类的过程中对父类已有的方法进行重写,而且不同的子类给出各自不同的实现版本)
    //2.对象造型(将子类对象当成父类型来使用)
    pet.shout()
    //可以通过if + as?将父类型安全的转换成子类型然后在调子类型特有的方法
    if let dog = pet as? Dog{
        dog.watchDoor()
    }else if let cat = pet as? Cat{
        cat.catchTheMouse()
    }else if let pig = pet as? Pig{
       pig.sleep()
    }
}
  • 如果要将父类型变量转换成子类型需要用AS运算符进行类型转换
  • 如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
  • 如果不能确认父类型的变量是哪种子类型可以用as?尝试转换

你可能感兴趣的:(Swift第二周学习总结)