接上次数组后面
1集合
集合也是一种容器,集合内数字没有顺序,是直接通过哈希码来查找
//集合通过哈希码找值
//哈希码(hash code)/散列码
//例子 MD5(数据库存储密码) /SHA-1 (是摘要而不是加密)
//1.1创建一个集合
var a :Set = [5,5,66,4,54,86,45,4,56,4]
print(a)
//1.2集合的遍历
for x in a {
print(x)
}
a.insert(1) //1.3在集合中插入一个数
a.remove(5)//1.4.1删除集合某个数
//a.removeAll()1.4.2全部删除
var b :Set = [64,6,45,64,6,4,64,6,4,6,4]
print(a.intersect(b))//1.5.1交集
print(a.union(b))//1.5.2并集
print(a.subtract(b))//1.5.3差集
print(a.isDisjointWith(b))//1.5.4判断2个集合是否相交,返回Bool(ture or false)
print(a.isSupersetOf(b))//1.5.5a是否是b的超集(a完全包含于b)返回Bool
2字典
字典:存放键值对组合的容器,字典中每个元素有2部分构成,冒号前面是键,后面是值
//2.1创建一个字典
var dict:[String: String] = ["thy":"你好","abs":"阿巴瑟"]
print(dict["abs"])
//字典元素可空,通过键获取对应的值(可空类型,因为给的键有可能没有与之对应的值)
//key ->value
dict["yld"] = "伊利丹"//2.2添加
print(dict)
//dict.removeValueForKey("thy")//2.3删除
//print(dict["thy"])
//或者doct["thy"] = nil同样删除
dict["thy"] = "好"
print(dict)
//2.4遍历
//2.4.1查找值
for value in dict.values {
print(value)
}
//2.4.2查找键
for key in dict.keys{
print("\(key)")
}
//2.4.3直接通过一个元组获得字典中的键和值(原始类型)
for(key,value) in dict {
print("\(key)-->\(value)")
}
函数
1关于函数的构建
完整的函数构建是:
func 函数名(外部参数名 内部参数名 :参数类型)->返回值类型{
函数执行
}
外部参数名是函数外使用的名称,内部参数名是在函数内使用的名称
func myMin(a x:Int, b y:Int)->Int{
//x,y为内部名
return x
tip:1如果参数名只有一个,说明内外参数名一样
tip:2从第二个参数开始,如果外部参数名为空,在调用函数时就可以直接输入
func hello(personname:String, _ alreadyGreeted:Bool = false) ->String {
var greet:String
if alreadyGreeted {
greet = "hello"+personname+"!"
}else{
greet = "怎么又是你"+personname+"!"
}
return greet
}
//调用函数
//函数名(参数值)
print("\(hello("古尔丹",true))")
//或者
//没有赋值默认为FALSE
let hel = hello("伊利丹")
print(hel+"噢,不好意思我看错了")
tip:3函数的参数可以是任意多个,使用可变参数列表,也可以不含参数
//使用函数求和
func sum(nums:Int...)->Int{
var total = 0
for num in nums {
total += num
}
return total
}
print(sum())
print(sum(1,2,3,4))
print(sum(231,51,5,4135,153,13,5,1435,435,43,541,53,1,231,351,30))
tip:4函数也可以使用元组返回多个值,也可以返回空值,如果为空,可以省略,也可以写->void
//使用函数求最大值和最小值
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
//循环输出array内的值
for value in array[1.. currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let b = minMax([1,5,45,4,534,534,4561,21,2,15,4,21]){
print(b.min)
print(b.max)
}else{
print("空的")
}
tip:5关于inout,函数的另一种输入输出方法
//交换值
func swap (inout x:Int,inout _ y:Int) -> Void {
let temp = x
x=y
y=temp
}
var x=5,y = 10
//函数调用的传参都是传值
//正常情况调用函数时,你不能传进去改变再拿出来的
//所有使用INOUT的参数都要加&
swap(&x, &y)
print("x=\(x),y=\(y)")
关于函数的几个练习
1.输入年月日,计算它是这年的第几天
func dayofyear(year:Int,_ mouth:Int,_ day:Int)->Int{
//数组传入12个值
var dayofmouth = [31,28,31,30,31,30,31,31,30,31,30,31]
if isLeapYear(year) {
//如果为闰年,2月为29天
dayofmouth[1] = 29
}
var sum = 0
for days in dayofmouth[0..Bool{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}
print("请输入某年某月某日,用空格隔开如:2016 8 8")
let y = inputInt()
let m = inputInt()
let r = inputInt()
print("\(y)年\(m)月\(r)日是\(y)年的第\(daysOfYear(y,m,r))天")
print("\(y)年\(m)月\(r)日是\(y)年的第\(dayofyear(y,m,r))天")
2.输入三个值,判断是否能构成三角形
func isvaildForTringle(a:Double,_ b:Double,_ c:Double)->Bool{
//assert 断言,如果满足条件,则继续往下执行,否则执行ASSert的内容,但只能用于打印错误信息,并不能参与计算
assert(a>0&&b>0&&c>0, "三角形的边长必须大于0")
return a+b>c&&a+c>b&&b+c>a
}
print(isvaildForTringle(2, 3, 4))
print(isvaildForTringle(1,2,3))
print(isvaildForTringle(3, 3, 3))
3.根据一个函数传入2个整数m,n计算m加到n
func reAdd(m:Int,_ n:Int)->Int {
let (m,n) = m > n ? (n,m):(m,n)
var sum = 0
for m in m...n{
sum+=m
}
return sum
}
print(reAdd(5,10))
4.根据不同时间,提示不同的问候语
func sayhello(name:String)->String{
//定义时间date类型为NSDATE()
let date = NSDate()
//拿到当前的日历
let cal = NSCalendar.currentCalendar()
//拿到Date类型的小时
let hour = cal.component(.Hour, fromDate: date)
var greet : String
//区间可以重叠,执行第一个满足条件的
switch hour {
case 0...5:
greet = "怎么还没睡啊"
//fallthrough,无条件执行下一条且不会去其他分支
case 6...10:
greet = "早起的鸟儿有虫吃"
case 11...13:
greet = "中午好"
case 14...18:
greet = "下午好"
default:
greet = "晚上好"
}
return name + "," + greet + "!"
}
print("\(sayhello("丹丹"))")
tip:5关于递归:递归是一个函数直接或者间接的调用函数自身
关键点:1.递归公式
2.收敛条件(什么时候停止)
3.一般用于循环难以解决的问题
例如:哈尼塔数
//几何倍数增长
var current = 1
func hanoi(n:Int,_ a:String,_ b:String,_ c:String){
if n > 0 {
//据说等人手动完成n=64时,地球就毁灭了
hanoi(n-1,a,c,b)
print("\(current),\(a)-->\(b)")
current += 1
hanoi(n-1, c, b, a)
}
}
print(hanoi(8,"a","b","c"))
2关于函数闭包
一个函数可以将另一函数作为参数,而在数学中我们称这为复合函数,而在传入函数时,调用无名函数即闭包函数,我们有多种表现方式
//使用加减乘除
func sum(a:Int,b:Int) -> Int {
return a+b
}
func mul(a:Int,b:Int) -> Int {
return a*b
}
func hello(x:Int,y:Int)->Int{
return 0
}
func foo(Array: [Int]) -> Int{
var sum = 0
for x in Array[0..Int)->Int{
var sum = 0
for x in (array) {
sum += x
}
return sum
}
//在Swift中函数是一种类型,这意味着函数可以作为变量或者常量的类型
//同理函数可以作为另一个函数的参数,也可以返回另一个函数
var fn = sum
fn = mul
fn = hello
let a = [2,31,15,4,5,45,4]
//当调用foo函数时第二个参数可以传什么?
//1.所有有自定义类型的(Int,Int) ->Int类型的函数
print(fortoo(a, fn: sum))
//2.传入二元运算符:+-*/%(因为运算符也是函数)
print(fortoo(a , fn: +))
//3.传入匿名函数(闭包)
//3.1完整闭包写法
print(fortoo(a, fn: {(a:Int,b:Int)->Int in
return a+b}))
//3.2省略掉类型个不必要的括号
print(fortoo(a, fn: {a,b in a+b}))
//3.3省略参数名
print(fortoo(a, fn: {$0+$1}))
//3.4尾随闭包
print(fortoo(a) { (a,b) -> Int in
return a + b })
print(fortoo(a) { $0+$1})
例子:根据字符串长短进行排序
var array = ["game","lol","cf","wow","dnf","pal","internationlization"]
//array.sortInPlace()
//array.sortInPlace(>)
//array.sortInPlace() { $0 > $1}
//如果函数的最后一个参数是闭包可以写成尾随闭包的形式
//也就是将闭包放到函数参数的圆括号外面写在一堆花括号中
//如果函数后面有尾随闭包且函数的括号中没有参数,那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
array.sortInPlace { $0 > $1}
print(array)
//字符串长短排序
array.sortInPlace { (one, two) -> Bool in//省略return
one.characters.count < two.characters.count
}
//极简版
array.sortInPlace{
$0.characters.count<$1.characters.count
}
//多条语句不能省略return
//根据字符串长短排序
array.sortInPlace{
if $0.characters.count == $1.characters.count {
return $0 < $1
}
return $0.characters.count<$1.characters.count
}
print(array)
3关于过滤,映射,合并
tip:$0表示取第一个参数的值,$1表示取第二个参数
1.过滤Filter
let array = [23,37,96,55,40,92,68,88]
//取得所有大于50的数
let newarray1 = array.filter {
$0 > 50
}
print(newarray1)
//取得所有偶数
let newarray2 = array.filter {
$0%2 == 0
}
print(newarray2)
2.映射Map
let array = [23,37,96,55,40,92,68,88]
let newarray3 = array.map { (x:Int) -> Int in
return x*x
}
print(newarray3)
//所有有数除2取整
let newarray4 = array.map {
$0/2
}
print(newarray4)
3.缩减、合并、规约
let array = [23,37,96,55,40,92,68,88]
//将所有数以加法合并,0表示开始值
let newarray5=array.reduce(0, combine: +)
print(newarray5)
//将所有数以乘法合并,1表示开始值
let newarray6=array.reduce(1, combine: *)
print(newarray6)
//找出数组的最大数
let newarray7 = array[1.. $1 ? $0 : $1
}
print(newarray7)
//字符串数组和并成一个字符串
let strarray = ["strom","gold","water","tree"]
let newarray8 = strarray.reduce("") {
//在每个字符串间用空格隔开,当和成一个类后再与后面的类合并
$0+" "+$1
}
print(newarray8)
关于类
个人觉得类就是从现实世界中选择某类东西,然后在电脑上给其命名,然后从现实中抽象出它的属性,它的行为等等,然后写进电脑,这样电脑就可以自己模拟现实中的这类事物。
感觉新建类,就有点自己是创世者一样,我可以创建我已知的,也可以创建我未知,但是幻想的事物,我只要赋予它我希望他有的属性,那它就是存在的了。
总之,新建类就是摆脱之前的虚无的逻辑,开始具体的搭建一个世界。
新建类
新建类:首先,一般来说,要新建类,首先需要新建一个SWIFT文件,将这个类的所有属性和动作都在里面以常量,变量,或者函数的形式表达清楚,而调用类,用来完成某件事则在main.swift内完成。
新建好文件后在里面定义类,创建新的类型,而变量在类内就该叫属性,函数在类内就叫动作。而这些都源于都现实事物的抽象。
定义好类后,就可以在main函数内创建对象,然后通过给对象发消息来解决问题,而这也就是我们所熟识的面向对象的编程。
举个栗子:
首先在新建一个Student.swift
class student {
//变量定义到类的外面就叫变量 - varliable
//变量定义到类的里面就叫属性 - property
//数据抽象,找到和学生相关的属性(找名词,和学生相关)
var name : String
var age : Int
//初始化方法(构造方法/构造器)-constructor,创建对象要使用的方法
//自己理解:给定义的类赋值
init (name:String,age:Int){
//self是自身属性
self.name = name
self.age = age
}
//函数写到类的外面就叫函数 - function
//函数写到类的里面就叫方法 - method
//行为抽象,找到和学生相关的方法(找动词),以动词命名
func eat()->Void{
print("\(name)正在吃饭")
}
func study(courName:String) {
print("\(name )正在学习\(courName).")
}
func playComputer(playname:String){
if age >= 13 {
print("\(name)正在玩\(playname)")
}else {
print("亲爱的\(name),我们建议你玩连连看")
}
}
}
然后在main.swift内创建,并发送信息
//步骤2:创建对象(调用初始化方法)
let stu1 = student(name: "玛法里奥", age: 100000)
//步骤3:给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("德鲁伊之道")
stu1.playComputer("炉石传说")
let stu2 = student(name: "安度因", age: 12)
stu2.eat()
stu2.study("论如何偷牌")
stu2.playComputer("炉石传说")
这就是一次简单的面向对象的编程。然后,开始尝试使用面向对象的方法解决一些稍复杂的问题。例如:之前的求泳池的造价问题,通过抽象,我们可以知道,这个问题关键在于解决同心圆的问题,那么我们需要新建一个类,它叫圆,它有一个对我们很有用的主要属性半径,也有一个对同心圆不怎么重要的属性:圆心;还有2个通过计算得到的属性周长和面积。知道这些,开始新建类:
Circle.swift内
//0.发现类
//-在对问题的描述中找名词和动词
//-名词会成为类或者类中的属性,动词会成为类中的方法
//1.定义类
//2.数据抽象(属性)
//3.行为抽象
//4.初始化方法
//public (公开)
//internal(内部的)-默认
//-private(私有的)
import Foundation
public class Circle {
//建议写成私有
//存储属性(保存和圆相关的数据属性)-stord property
private var radius:Double
var center : point
//定义类要求所有的属性都要有值
init(center:point,radius:Double){
self.center = center
self.radius = radius
}
//要公开方法要先公开类
//Swift和oc一般用名词表示得到某值
//通常获得某个值得方法都可以设计成计算属性
//计算属性(通过对存储属性做运算得到的属性)-computational property
var perimeter:Double {
//圆的周长只是一个只读属性
//所以此处只有get{}没有set{}
get {return 2 * M_PI * radius}
}
var area : Double {
get{return M_PI * radius * radius}
}
}
然后在main.swift内解决问题:
//2创建对象
let r = 5.5
let small = Circle(radius: r)
let big = Circle(radius: r+3)
//3.对对象发消息(调用对象方法)
let fancePrice = big.perimeter*1.5
//%。1f是保留小数
print(NSString(format: "围墙造价为:¥%.1f元",fancePrice))
let aislePrice = (big.area-small.area)*3.5
print(NSString(format: "过道造价为:¥%.1f元", aislePrice))
再使用该方法解决猜数字游戏的问题:
首先顶一个一个机器人类,它能产生随机数,它能计算回合数,它能对你输的数字进行判断,并给出回应。
Robot.swift
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
}
}
main.swift内我们来玩这个游戏
//创建一个机器人
let r = Robot()
//定义一个参数
var isgameover = false
repeat{
print("请输入一个数")
//输入方法前上一篇有详细介绍
let thyAnswer = inputInt()
isgameover = r.judge(thyAnswer)
print(r.hint)
}while !isgameover
if r.counter>7 {
print("智商捉急")
}
猜数字的游戏就这样完成了。接下来完成一个稍复杂的网页上面的回合制自动攻击的小游戏,奥特曼打怪兽。
首先定义奥特曼类:
//随机数类,可以全局调用
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 }
set { _mp = newValue > 0 ? newValue : 0}
}
init(name: String, hp: Int, mp: Int) {
_name = name
_hp = hp
_mp = mp
}
//攻击行为
func attack(monster: Monster) {
let injury = randomInt(15, 20)
monster.hp -= injury
if _mp >= 100{
_mp = 100
}else {
_mp += 5
}
}
//大招行为
func hugeAttack(monster: Monster) {
let injury = monster.hp * 3 / 4 >= 50 ? monster.hp * 3 / 4 : 50
monster.hp -= injury
}
//魔法攻击行为
func magicalAttack(monsters: [Monster])->Bool {
if _mp >= 30 {
for monster in monsters {
//对敌方全体造成伤害
if monster.isAlive {
let injury = randomInt(5, 15)
monster.hp -= injury
}
}
_mp -= 30
return true
}
return false
}
}
怪兽类
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 }
}
init(name: String, hp: Int) {
_name = name
_hp = hp
}
//攻击
func attack(ultraman: Ultraman) {
let injury = randomInt(5, 10)
ultraman.hp -= injury
}
}
main内进行对打:
// 奥特曼打小怪兽
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: 300, mp: 80)
//创建多个怪兽
let mArray = [Monster(name: "巴尔塔星人", hp: 120),
Monster(name: "哥斯拉", hp: 250),
Monster(name: "艾蒙", hp:180),
Monster(name: "萨格拉斯", hp:200)]
//回合数
var round = 1
repeat {
print("========第\(round)回合========")
let m = pickOneMonster(mArray)
let factor = randomInt(1, 10)
switch factor {
case 1...7:
print("\(u.name)奥特曼使用了普通攻击")
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:u.hugeAttack(m)
print("\(u.name)奥特曼使用七彩光")
if m.isAlive {
m.attack(u)
}
}
print("\(u.name)奥特曼生命值: \(u.hp)")
print("\(u.name)奥特曼魔法值: \(u.mp)")
for m in mArray{
print("\(m.name)小怪兽生命值: \(m.hp)")
}
round += 1
} while u.isAlive && !isAllDead(mArray)
if u.isAlive {
print("\(u.name)奥特曼获胜!!!")
}
else {
print("小怪兽获胜!!!")
}
做完这个,来说下关于类的注释
例如:之前的学生类
//存储属性通常是PRIVATE的,因为数据要保护起来
//方法一般是PUBLIC的,因为方法是对象接受的消息
//如果自定义的类没有打算在其他项目中使用,可以不写访问修饰符
//直接使用默认的internal修饰符表示在本项目中公开对其他项目私有
func <(one:Student,two:Student)-> Bool {
return one.age < two.age
}
///学生类
public class Student {
private var _name:String
private var _age : Int
///姓名隐去最后一个字符
public var name:String {
get{
let value = _name.characters.count>2 ? -2:-1
//取出字符串的部分
let displayName = _name.substringToIndex(_name.endIndex.advancedBy(value))
return displayName+"x" }
}
public var age :Int {
get{return _age}
}
/**
初始化方法
- parameter name :姓名
- parameter age : 年龄
*/
public init(name:String,age:Int){
self._name = name
self._age = age
}
/**
吃饭
- parameter food : 吃的什么
*/
func eat(food:String){
print("\(_name)正在吃\(food))")
}
/**
学习
- parameter courseName: 课程名称 如果有返回值
- returns: 学会了返回true 没有返回false
*/
public func study(courseName:String){
print("\(_name)正在学习\(courseName).")
}
/**
看电视
- parameter tv:电视名
*/
public func watchJapaneseAV(tv:String){
if _age > 18 {
print("\(_name)正在看\(tv)")
}else {
print("请看熊出没")
}
}
}
通过这样的注释,自己或者别人在使用该类时,会看到注释内的字符提示,这极大的提高了类的可读性,方便别人理解。
在计算机中,它没办法自己计算分数,那么我们来设计一个分数的计算类,来进行分数计算。
创建分数类
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
//短除法优化求最大公约数(欧几里得算法)
if x > y {
return gcd(y,x)
}
else if y%x != 0 {
return gcd(y%x, x)
}
else{
return x
}
}
class Ftaction {
private var _numerator:Int
private var _denominator:Int
init (numerator:Int,denominator:Int){
assert(denominator != 0)
_numerator = numerator
_denominator = denominator
normalize()
}
var info:String {
get{return _numerator == 0 || _denominator == 1 ? "\(_numerator)" : "\(_numerator)/\(_denominator)"}
}
func multiply(other:Ftaction)->Ftaction{
let numerator1 = other._numerator * _numerator
let denominator1 = other._denominator * _denominator
return Ftaction(numerator: numerator1, denominator: denominator1).simplify()
}
func divide(other:Ftaction)->Ftaction{
let numerator1 = other._denominator * _numerator
let denominator1 = other._numerator * _denominator
return Ftaction(numerator: numerator1, denominator: denominator1).simplify()
}
func addition(other:Ftaction)->Ftaction{
return Ftaction(numerator: _numerator*other._denominator+other._numerator*_denominator, denominator: _denominator*other._denominator).simplify()
}
func subtraction(other:Ftaction)->Ftaction{
return Ftaction(numerator: _numerator*other._denominator-other._numerator*_denominator, denominator: _denominator*other._denominator).simplify()
//链式编程
}
func normalize() -> Ftaction{
if _denominator < 0{
_numerator = -_numerator
_denominator = -_denominator
}
return self
}
func simplify() -> Ftaction {
if _numerator == 0 {
_denominator = 1
}else {
let x = abs(_numerator)
let y = abs(_denominator)
let g = gcd(x, y)
_numerator /= g
_denominator /= g
}
return self
}
}
//运算符重载(为自定义的类型定义运算)
//+—*/是自带的函数,而我们可以通过重载的方式对它们进行修改
func +(one: Ftaction,two:Ftaction)->Ftaction{
return one.addition(two)
}
func -(one: Ftaction,two:Ftaction)->Ftaction{
return one.subtraction(two)
}
func *(one: Ftaction,two:Ftaction)->Ftaction{
return one.multiply(two)}
func /(one: Ftaction,two:Ftaction)->Ftaction{
return one.divide(two)
}
main.swift内
let a = Ftaction(numerator:4, denominator:-5)
print(a.info)
let b = Ftaction(numerator: 5, denominator:4)
print(b.info)
let c=a+b
print(c.info)
let d = a/b
print(d.info)
let e = a.multiply(b)
print(e.info)
let f = a.subtraction(b)
print(f.info)
这样我们就可以在里面进行分数的计算了。
关于类的继承
我们发现很多事物有许多共同的属性,比如:学生和老师,他们都是人,不同之处是一个学,一个教,他们的共有属性太多,而我们为了代码避免重复这个坏味,所以选择在他们之前新建一个人类。而让,学生和老师通过继承人类,来获得人的属性。
tip:
继承:从已有的类中创建出新类的过程,提供继承信息的类父类(超类/基类)
得到继承信息的称为子类(派生类/衍生类)
通常子类除了得到父类的继承信息还会增加一些自己特有的东西
所有子类的能力一定比父类更强大
继承的意义在于子类可以复用父类的代码并且增强系统现有的功能
首先,创建一个人类:
//我们经常通过枚举的方式来创建新的类型
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)正在吃饭")
}
}
学生类继承人类
//学生继承人
class Student:Person {
//专业
var major:String
init(name:String,age:Int,major:String,gender:Gender){
self.major = major
//超类:继承他的父类
super.init(name: name, age: age, gender: gender)
}
//学习
func study(courseName:String) {
print("\(name)是\(major)专业的学生")
print ("\(gender == .Male ? "他":"她")正在学习\(courseName)")
}
}
老师类继承人类
class Teacher:Person {
//职称
var title:String
init(name:String,age:Int,title:String,gender:Gender){
self.title = title
super.init(name: name, age: age, gender: gender)
}
//教
func teach(courseName:String){
print("\(name)\(title)正在教\(courseName)")
}
}
main.swift内:
let p1 = Person(name: "金", age: 15, gender:.Male)
p1.eat()
let p2 :Person = Student(name: "木", age: 18, major: "计算科学与技术", gender: .Female)
p2.eat()
(p2 as!Student).study("万物生")
//tip:
//我们可以将子类型的对象赋给父类型的变量(因为子类和父类之间是IS-A关系)
//学生是人,老师是人,所以学生老师的对象都可以赋值给人类型的变量
//如果要将父类型的变量转换为子类型需要用AS运算符进行类型转换
//如果确认父类型的变量中就是某 子类型的对象可用AS!转换
//如果不确定父类型的变量中是哪种子类型可用as?尝试转换
//不知道是什么类型时用as?转换
//如果确定知道类型时as!转换
if let temp = p2 as? Teacher {
temp.teach("java")
}else {
print("\(p2.name)不是老师!")
}
let p3 = Teacher(name: "水", age: 21, title: "灵", gender: .Female)
p3.eat()
p3.teach("冲浪术")
关于多态
多态:同样的对象类型(pet类型)接受相同的消息(调用相同的方法),但做了不同的事这就叫做多态(polymorhpism),目的是解耦合,
关键1.为方法重写(子类在继承父类的过程中对父类已有的方法进行重写。而且不同的子类给出各种不同的实现版本)
2.对象造型(将子类型对象当成父类型来使用)
通过一个养宠物的例子说明:
宠物
enum Gender {
case Male
case Female
}
import Foundation
class Pet {
var nickName:String
var gender :Gender
var age :Int
init (nickName:String,gender:Gender,age:Int){
self.nickName = nickName
self.age = age
self.gender = gender
}
func play() {
print("\(nickName)正在玩")
}
func eat() {
print("\(nickName)正在吃东西")
}
func shout(){
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)
}
func catchTheMouse(){
print("\(nickName)正在抓老鼠")
}
//父类有的方法,子类要重新实现,要使用方法重写override
//在方法前添加override
//重写有时也被翻译为置换,覆盖,覆习
override func shout() {
print("\(nickName):喵喵...")
}
override func play() {
//play()自己调自己,递归,错误
// super.play()//调用父类
print("\(nickName)正在玩毛线球。")
}
}
狗
class Dog: Pet {
var hairColor :String
var isLarge:Bool
init(nickName: String, gender: Gender, age: Int,hairColor:String,isLarge:Bool) {
self.hairColor = hairColor
self.isLarge = isLarge
super.init(nickName: nickName, gender: gender, age: age)
}
override func play() {
super.play()
print("\(nickName)正在追飞盘")
}
override func shout() {
print("\(nickName):汪汪.....")
}
func lookDoor(){
if isLarge{
print("\(nickName)正在看门")
}
else{
print("\(nickName)太小了谁也打不过")
}
}
}
main.swift内
let petsArray = [
Cat(nickName: "花花", gender: .Female, age: 3, hairColor: "黄色"),
Dog(nickName: "旺财", gender: .Male, age: 2, hairColor: "黑色", isLarge: true),
Dog(nickName: "大黄", gender: .Male, age: 1, hairColor: "黄色", isLarge: false)
]
for pet in petsArray {
// pet.eat()
// pet.play()
pet.shout()
//可以通过if——as?将父类型安全的转换成子类型然后在调用子类特有的方法
if let dog = pet as? Dog {
dog.lookDoor()
}
else if let cat = pet as?Cat {
cat.catchTheMouse()
}
}
就这些了。