Swift第二周学习任务
一.容器类(集合,字典)
1.集合
var collectionA: Set<Int> = [2, 3, 4, 5, 1, 1, 2, 3] //[2, 3, 5, 4, 1]
collectionA.insert(100) //添加元素100到集合中
collectionA.remove(2) //删除元素值为2的元素
var collectionB: Set<Int> = [2, 3, 1]
print(collectionA.intersect(collectionB)) //输出两个集合的交集
print(collectionA.union(collectionB)) //输出两个集合的并集
print(collectionA.subtract(collectionB)) //输出集合A有B没有的元素(差集)
集合存储方式为哈希存储,在集合内每个数都是无序的。并且每个元素值只能有且只有1个.上述集合中,集合中的元素相同的数只会被存储一次。[2, 3, 5, 4, 1],在存储空间中按照要求任意存放
哈希码(hash code)/散列码
MD5 / SHA-1 这类存储方式一般用于大型网站上对用户密码的一种映射关系,将用户的密码进行只能够单向的映射操作.达到加密的作用
var a: Set<Int> = [1, 2, 3, 1, 2, 5]
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)) // 判断两个集合是否相交
2.字典
字典其原理就是通过一种值查找另一个值的过程。值通过字典存储,形成键值对。每一个键值对都是唯一的,一个唯一的key对应一个value(可空)。
var dict: [String: String] = ["abacus": "算盘", "abnormal": "异常的", "hello" : "你好", "good": "好的"] // 定义一个字典
dict["haha"] = "哈哈" // 添加键值对,添加字典元素
dict["hello"] = nil // 删除键值对,删除字典元素
dict.removeValueForkey("hello") // 与上面方法效果一样
dict[good] = "不好" // 修改value
字典的遍历方式有3种,第一种遍历字典拿到每一个key。第二种遍历拿到每个元素的value。第三种遍历拿到一个元组,(key, value)。
for key in dict.key {
print("\(key) -> \(dict[key])")
}
for value in dict.value {
print(value)
}
for (key, value) in dict {
print("\(key) -> \(value)")
}
二.函数
1.定义函数与基本用法
func 函数名(参数列表) ->返回类型 {函数的执行体}
Swift中函数的参数可以设定默认值
如果调用函数的时候没有给该参数赋值就直接使用默认值
可以使用元组(tuple)让函数一次返回多条数据
inout - 输入输出函数(不仅将数据传入函数还要从函数中取出数据)
与C语言中的指针作用相似
func creatX(inout x: Int) {
x = 1000
}
var x = 1
creatX(&x)
print(x)
断言:当程序运行到自己预先加的断言时不成立时,程序崩溃。控制台会打印断言中的语句
assert(m >= n, "m必须大于等于n")
2.递归函数
重点:1.确定递归公式 2.确定收敛条件
原理:递归函数通过一个函数直接或间接得调用自身函数,实现函数计算功能
//求阶乘
func f(n: Int) -> double {
if n == 1 && n == 0 {
return 1 //当n = 1 或者 n = 0 时,跳出递归公式,相当于是n * n - 1 * ... * 1,没调用一次得到一个当前n值做乘法运算
}
return n * f(n - 1)
}
//汉诺伊塔游戏
func hanoi(n: Int, _ a: String, _ b: String, _ c: String) {
if n > 0 {
hanio(n - 1, a, c, b)
print("\(a) -> \(b)")
hamoi(n - 1, c, b, a)
}
}
3.函数的参数为函数
1.定义
在Swift中函数是一种类型.这也意味着函数可以作为变量或常量的类型
同理函数也可以作为另一个函数的参数和返回值
2.闭包(匿名函数)
func foo(array: [Int], fn:(Int, Int) -> Int) -> Int
//foo函数中,参数传入一个数组和一个函数, 返回一个Int。这个函数中的函数就称为闭包(匿名函数)。
在这个函数中,第二个参数可以传入的类型有3种
1.使用自定义的函数类型, 新定义一个函数
2.传入二元运算符:+, -, *, /, %(在Swift中,二元运算符也是一个函数)
3.传入匿名函数(闭包), 函数没有名字
//1. 完整的闭包写法
foo(a, fn:{(a, b) -> Int in return a + b}
//2.省略闭包写法(在Swift中,一切能省则省, 类型可以省略, 括号也可以省略, 包括参数名也能省略)
//2.1 省略类型
foo(a, fn:(a, b) in a + b )
//2.2 省略括号
foo(a, fn:{a, b in a + b})
//2.3 省略参数名
foo(a, fn: { $0 + $ 1})
3.尾随闭包
foo(a){ $0 + $ 1}// 这个写法的条件是, 只有函数参数的最后一个是另一个函数时, 才能使用尾随闭包写法
闭包 -就是跟Java和C#中的Lambda函数(Lambda表达式), JavaScript中的匿名函数, C / C++ / Objective - C中的Block起相同作用的东西, 它的存在的意义是实现代码的解耦合.(实现回调的编程模式)
三.面向对象编程
1.对象, 类和消息
对象:接收消息的单元
1.一切皆为对象
2.对象都有属性和行为
3.对象都属于某个类
4.每个对象都是独一无二的
类:对象的蓝图和模板类是抽象的, 对象是具体的
消息: 对象之间通信的方式, 通过对象互发消息可以构造出复杂的系统
2.访问修饰符
Public - 公开的
internal - 内部的(默认)
private - 私有的
存储属性 -> private 私有化, 不允许随便修改, 将数据保护起来
计算属性 -> public 公开, 因为方法是对象接收的消息, 需要调用
方法一般为公开, 对象一般为私有. 如果自定义的类没有打算在其它项目中使用, 可以不写访问修饰符,默认为internal, 表示在本项目中公开对其它项目使用
3.定义和使用类
1.定义一个类, 定义一个类就可以创建出新的类型
2.数据抽象 - 定义类里成员的属性
3.初始化方法 - 初始化成员变量
4.行为抽象 - 给类写方法, 完成不同的动作(作用)
5.也可以给类添加一个计算属性.(通过对存储属性作运算得到的属性)
var name: String // 存储属性, 存储相关的数据的属性
var sellPrice: Double {
get{ return 0.87 * price} // get表示读
set{ return sellPrice = newValue}
}// 计算属性, 通过对存储属性做运算得到的属性
init(name: String, age: Int) {
self.name = name
self.age = age //在同一个类中可以拥有多个init构造方法, 但最终还是会被调用一个指派初始化方法. 相当于在其他init方法中, 再调用一次init方法, 完成初始化
}
4.类扩展
原理: 在一些特殊的情况下, 你在一个类中需要一种特定的功能, 这个类不能帮你实现目的。这个时候你需要利用类扩展(extension), 来现场添加这项功能
//目标是讲Point中的成员类型由double -> CGPoint
extension Point { // Point代表需要扩展的类
var cgPoint : CGpoint { // 返回的值类型
get { return CGPointMake(CGPoint(point.x), CGPoint(point.y))} //返回一个CGPoint
}
}
5.运算符的重载
为自定义的类型定义运算符, 写在类的外边
在Swift中运算符算是一种函数(方法), 相当于重写运算符的方法
//实现两个分数的加法运算, addTo函数实现两个分数相加的功能
func +(one: Fraction, two: Fraction) -> Fraction {
return one.addTo(two) // 返回一个值为one + two 的分数
}
四. 继承
1.概念
根据已有的类, 创建新类的过程
提供信息的称为父类(也叫超类, 基类)
得到继承信息的称为子类(也叫派生类, 衍生类)
一般情况下, 子类一般除了得到父类的继承信息外, 还会增加一些属于自己特有的东西, 因此子类的能力比父类更强大
继承的意义主要是减少代码的复用度, 子类可以直接使用父类的属性和方法, 还可以增强系统现有的功能
IS-A关系
as!
as?
用法解释
let person = Person(name: "王钢蛋", age: 23)
let stu = Student(name: "钢蛋王", age: 23, lesson: "Swift开发")
let doc = Doctor(name: "王医生", age: 23, title: "开刀手")
//其中Person是父类, Student, Doctor是子类
//可以将子类型的对象赋值给父类型的变量(父类和子类的关系为IS-A)
let stu2 : Person = Student(name: "钢蛋王", age: 23, lesson: "IOS网络课程学习") // stu2对象是一个Person对象
(stu2 as! Student).study // 如果我确定stu2是学生, 可以执行学生独有的方法, 可以使用as!方法转换, 将stu2对象类型由Person转化成student类型
//如果判断不出来是否为某一种子类的时候, 但是你需要它调用那个类的方法时, 需要用as!来判断, 返回的是一个Student?类型, 如果是Student类型, 返回true, 否则返回false
if let stu2 as? Student {
print("\(stu2.name)是学生") // 可以通过这种方式, 安全的将父类型的转化成子类型, 然后才能调用子类型的特有方法
}
2.重写
父类有的方法子类可以重新实现, 这个过程叫做重写
重点: 需要在方法前添加 override关键子
重写计算属性时, 也必须需要加上关子 override
重写有时也被称为置换, 覆盖, 覆写
五.多态
1.概念
同样对象类型(父类类型), 接收相同的消息或方法时, 却做出了不同的事情, 这就叫做多态(polymorphism)
2.实现多态的步骤
1.在子类中重写父类的方法, 并且需要在各个子类的该方法中实现不同的版本
2.对象造型(意思就是将所有子类对象当次父类对象来用, 来调用重写的方法)
for book in booksArray {
print("\(book.name)-原价:\(book.price), 售价:\(book.sellPrice)") // 在bookArray中, 分别存的一系列的子类对象, 重写没个子类的计算属性, 导致每个子类sellPrice属性返回的值都不一样, 实现多态
}
六.其它知识
1.短除法求x,y最大公约数(利用递归)
原理: x和y的最大公约数跟y%x和x最大公约数是一样的
func gcd(x: Int, _ y: Int) -> Int {
if x > y {
gcd(y, x) // 将大的数放到第一个参数位置上
}
else if y % x != 0 { // 不能整除则不能得到最大公约数,继续递归做判断
return gcd(y%x, x)
}
else { // 判断出最大公约数
return x
}
}
2.文档注释
方式一. ///通常用来注释类或者消息
方式二.
/**
吃饭
- parameter food: 食物
- returns: 返回正确true, 错误false
*/
func eat(food: String) -> Bool {
}