Swift入门笔记(二)

枚举

使用enum来创建一个枚举
像类和其他所有命名类型一样,枚举可以包含方法

enum Rank: Int {	
	case Ace = 1	
	case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
	case Jack, Queen, King
func simpleDescription() -> String {
	switch self {
		case .Ace:    return "ace"
		case .Jack:   return "jack"
		case .Queen: return "queen"
		case .King:   return "king"
		default:        
			return String(self.rawValue)
				}
			}
}
print(Rank.Six.rawValue)
print(Rank.Jack.simpleDescription())

上例中枚举原始值的类型是Int
只需要设置第一个原始值,剩下的原始值会按照顺序赋值
也可以使用字符串或者浮点数作为枚举的原始值
使用rawValue属性来访问一个枚举成员的原始值

枚举的成员值是实际值,并不是原始值的另一种表达方法
为防原始值没有意义,可以不设置原始值

结构体

使用struct来创建一个结构体
Swift 中类和结构体有很多共同点

定义属性用于储存值
定义方法用于提供功能
定义下标用于通过下标语法访问值
定义初始化器用于生成初始化值
通过扩展以增加默认实现的功能
符合协议以对某类提供标准功能

与结构体相比,类还有如下的附加功能:

继承:允许一个类继承另一个类的特征
类型转换允许在运行时检查和解释一个类实例的类型
取消初始化器允许一个类实例释放任何其所被分配的资源
引用计数允许对一个类的多次引用

它们之间最大的一个区别就是结构体是传值,类是传引用

使用struct来创建一个结构体
所有结构体都有一个自动生成的成员逐一初始化器,用于初始化新结构体实例中成员的属性。
新实例中各个属性的初始值可以通过属性的名称传递到成员逐一初始化器之中

值类型和引用类型

Swift中,类型分为两类

第一种是值类型,该类型的每个实例持有数据的副本,并且该副本对于每个实例来说是独一无二的一份,比如结构体(struct)、枚举(enum)、元组(tuple)都是值类型

第二种是引用类型,该类型的实例共享数据唯一的一份副本(在native层面说的话,就是该类型的每个实例都指向内存中的同一个地址),类(class)就是引用类型。

它们有什么不同?

值类型最基本的特点就是复制
这影响到它的赋值、初始化、传参等操作

struct S { 
var data: Int = -1 
}
var a = S()
var b = a                       
a.data = 42                     
print("\(a.data), \(b.data)")

引用类型的复制行为其实是隐式的创建了一个共享的实例,作为原始类型的引用
所有变量都会引用唯一的那个共享实例的数据,当改变变量中任何一个的数据,都会同样作用于原始类型的数据

class C { var data: Int = -1 }
var x = C()
var y = x
x.data = 42     
print("\(x.data), \(y.data)")

执行结果
Swift入门笔记(二)_第1张图片

值类型用途

  • 选择值类型的一个很重要的原因是可以比较容易的理解和掌控代码
  • 如果使用值类型,那么都是和唯一的数据值、类型的副本打交道
  • 对数据的修改只作用于数据所属的类型实例,所以可以不用担心因为在某个地方对数据的修改而影响到其他地方的数据
  • 在多线程环境中非常有用,在多线程下,不同的线程有可能会在不知情的情况下改变数据,发生这种Bug后,调试起来非常困难

使用值类型的情形:

使用==运算符比较实例数据的时候。
想单独复制一份实例数据的时候。
当在多线程环境下操作数据的时候。

使用引用类型(class)的情形:

当使用Cocoa框架时,很多API都是NSObject的子类,必须要使用引用类型
当使用===运算符判断两个对象是否引用同一个对象实例的时候。
当上下文需要创建一个共享的、可变的对象时。

使用class和类名来创建一个类
类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类
方法和函数声明也一样
函数:通过名字来进行直接调用,独立的功能模块
方法:通过名字来进行调用,但它跟一个类对象相关联,可以操作类内部的数据

创建类Shape

class Shape {
	var numberOfSides = 0
	func simpleDescription() -> String {
		return "A shape with \(numberOfSides) sides."
	}
}

创建一个类的实例

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

要点

  1. 系统要求存储属性必须初始化
  2. 可选值可以不初始化,默认将设置为nil
  3. 如果非可选类型存储属性不设置默认值,则必须在初始化方法中对其进行初始化如果非可选类型存储属性不设置默认值,则必须在初始化方法中对其进行初始化
  4. 类必须自己写初始化方法,用来初始化没有默认值的非可选存储属性类必须自己写初始化方法,用来初始化没有默认值的非可选存储属性
  5. 结构体系统默认会添加初始化方法,也可以自定义结构体系统默认会添加初始化方法,也可以自定义
  6. 子类如果没有自己的初始化方法,系统默认使用父类的初始化方法,一旦有了自己的初始化方法,或者重写了父类的初始化方法,则父类的所有初始化不能被子类调用子类如果没有自己的初始化方法,系统默认使用父类的初始化方法,一旦有了自己的初始化方法,或者重写了父类的初始化方法,则父类的所有初始化不能被子类调用
  7. 可以给子类添加和父类相同的初始化方法,但需要加上override 修饰可以给子类添加和父类相同的初始化方法,但需要加上override 修饰
  8. 重写父类的convenience修饰的便利初始化方法,不需要加override重写父类的convenience修饰的便利初始化方法,不需要加override

类的初始化
使用 init 来创建一个构造器
Swift入门笔记(二)_第2张图片
子类的定义方法是在它们的类名后面加上父类的名字,用冒号分割
创建类的时候并不需要一个标准的根类,所以可以忽略父类。
子类如果要重写父类的方法,需要用override标记
Swift入门笔记(二)_第3张图片
属性可以有 getter 和 setter,这称之为计算属性
计算属性 (闭包) 不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值
即:计算属性可以根据所设置内容,进行一些修改或计算

Swift入门笔记(二)_第4张图片
构造器 init 执行了三步:

  1. 设置子类声明的属性值
  2. 调用父类的构造器调用父类的构造器
  3. 改变父类定义的属性值,其他的工作比如调用方法、getters和setters也可以在这个阶段完成改变父类定义的属性值,其他的工作比如调用方法、getters和setters也可以在这个阶段完成

这3个步骤顺序不能调换,必须按照这个流程来进行初始化

类的初始化器有两种, 分别是:
1、Designated Initializer(指定初始化器)
指定初始化器是类的最主要的初始化器
它会将类中所有的属性赋值初始化,并且一路往上调用类的父类的指定初始化器去初始化它们各自引入的属性
类可以有多个指定初始化器,也可只有一个,但必须至少有一个

2、Convenience Initializer(便利初始化器)

1)程序在实际使用过程中,对象和对象的实例变量的值可能不同,可以在 init 方法调用的时候传入一个需要的数据,内部再转换
2)将对象用一些默认值进行初始化来让它们适合某种使用场景

便利构造器是一种快速创建对象的方式
本质上是把初始化方法做了一次封装,方便外界使用
便利初始化器不能被子类重写或从子类中以super的方式被调用
一个类可以没有便利初始化器

初始化器调用规则:

  1. 子类的指定初始化器必须要调用父类的指定初始化器
  2. 便利初始化器必须调用同一类中定义的其他指定初始化器便利初始化器必须调用同一类中定义的其他指定初始化器
  3. 便利初始化器必须最终以调用一个指定初始化器结束便利初始化器必须最终以调用一个指定初始化器结束

Swift入门笔记(二)_第5张图片

required 关键字
required修饰符只能用于修饰类初始化方法。
当子类含有异于父类的初始化方法时(初始化方法参数类型和数量异于父类),子类必须要实现父类的required初始化方法,并且使用required修饰符而不是override
当子类没有初始化方法时,可以不用实现父类的required方法
最大的好处是可以保证依赖于某个指定初始化方法的便利初始化方法一直可以被使用

可失败构造器
init初始化方法可以通过在init关键字后面加上?或!将其变为可失败初始化方法
表示某对象的初始化过程可能失败,并返回 nil
可失败构造器/初始化方法解决了以前在Swift中只能通过工厂方法捕获构造或初始化失败情况的问题
使用可失败构造器可极大程度的统一Swift中的构造对象语法,消除了构造器与工厂方法之间混乱、重复的冗余语法,使Swift更加简洁。
随着可失败构造器这一特性的加入,Swift将对大多数Cocoa中带NSError参数的工厂初始化方法进行调整,从而加强Swift中构造对象语法的统一性,给开发者带来更好的开发体验
Swift入门笔记(二)_第6张图片

属性观察者
如果不需要计算属性,但是需要在设置一个新值之前或者之后运行代码,可以使用属性观察者:
willSet
didSet
属性观察者类似于触发器,用来监视属性的除初始化之外的属性值变化,当属性值发生改变时可以对此作出响应。
特点:

  • 不仅可以在属性值改变后触发didSet,也可以在属性值改变前触发willSet。
  • 给属性添加观察者必须要声明清楚属性类型,否则编译器报错。
  • willSet可以带一个newName的参数,没有的话,该参数默认命名为newValue
  • didSet可以带一个oldName的参数,表示旧的属性,不带的话默认命名为oldValue
  • 属性初始化时,willSet和didSet不会调用。只有在初始化上下文之外,当设置属性值时才会调用。
  • 即使是设置的值和原来值相同,willSet和didSet也会被调用
    Swift入门笔记(二)_第7张图片

类型检查和转换
==is == 操作符用于判断一个实例是否是某个类的类型
==as == 操作符用于转换一个实例到某个类的类型
返回类型是Bool

is用来做类型检查
is也可以用来检查某个类是否遵循了某个协议

as 用来做类型转换
如果不确定类型转换能否成功,可以在as后面加问号“?”

//基类,人类
class Human{
}
 
//男人类
class Man: Human{
}
 
//女人类
class Woman: Human{
}
let man = Man()
let woman = Woman()
var arr = [man,woman]
 
for people in arr {
    if people is Man {
        print("这是个男人")
    }else if people is Woman {
        print("这是个女人")
    }
}
let man = Man()
let woman = Woman()
var arr = [man,woman]
 
for people in arr {
    if let m = people as? Man {
        print("这是个男人")
    }else if let w = people as? Woman {
        print("这是个女人")
    }
}

不确定类型
Any 和 AnyObject 类型
AnyObject可以代表任何class类型的实例。
Any可以表示任何类型,包括AnObject和其他数据类型,除了方法类型(function types)。
注意:
只有当明确的需要它的行为和功能时才使用Any和AnyObject
在代码里使用明确的类型比较好

上课的代码

闭包

import Foundation

// ---------------------------------------------------------
// 闭包基础知识
// 1. 闭包可以理解为无名函数,其实例如下。不带参数的闭包
var b1 = {
    print("这是闭包")
}
b1()    // 使用闭包

// 2. 带参数的闭包,参数的闭包,使用关键字 in 分隔参数与闭包体
var b2 = {
    (param: String) in
    print("闭包参数是:\(param)")
}
b2("你好")


// 3. 带参数和返回值的闭包
var b3 = {
    (param: String) -> String in
    return "闭包参数是:\(param)"
}
let rst3 = b3("你好")
print("闭包返回值是:\(rst3)")


// 4. 闭包可自带参数
var b4 = {
    (p1: String, p2: String) -> String in
    return p1+p2
}("Hello", "Wrold")
print(b4)


// 5. 闭包简化1,自动推导参数和返回值类型 可以根据参数推断。
var s1 = {
    (p1, p2) in
    return p1+p2
}("Hello", "Wrold")
print(s1)


// 6. 闭包简化2,如果函数体只包含一句 return 代码,可省略 return
var s2 = {
    (p1, p2) in
    p1+p2
}("Hello", "Wrold")
print(s2)


// 7. 闭包简化3,参数名称简写,可通过$0$1...引用闭包参数值
var s3 = {
    $0+$1
}("Hello", "Wrold")
print(s3)



// --------------------------------------------------------
// 带有闭包参数的函数和尾随闭包
// 1. 第1和2个参数是整数,第3个参数是闭包进行数学计算,返回计算结果

func myOpreation(_ a: Int , _ b: Int, operation: (Int , Int) -> Int) -> Int {
    let res = operation(a, b)
    return res
}

//实现一个闭包
//let multipyClosure = {
//    (a: Int, b: Int) in
//    a * b
//}

// 简化
let multipyClosure:(Int, Int) -> Int = {
    $0 * $1
}

//将闭包作为参数传递
var rst = myOpreation(4, 2, operation:multipyClosure)
print(rst)


// 不定义闭包变量,直接使用inline展开
rst = myOpreation(3, 3) { (a, b) -> Int in
    a * b
}
print(rst)


// 简化
rst = myOpreation(4, 4, operation: {
    $0*$1
})
print(rst)


// 尾随闭包,如果闭包是作为函数的最后一个参数,可以将闭包后置到函数体外部
rst = myOpreation(5, 5) {
    $0*$1
}
print(rst)


// -------------------------------------------------------------
// 闭包在集合中的应用

// 数组提供了一个排序函数,sorted().使用的是默认规则,当然我们也可以定制排序规则。

let names = ["LiWei", "MaYun", "Bob", "ZhouXingChi", "W"]
let rst4 = names.sorted()
print(rst4)

//更改排序规则 其实就是利用了函数重载,具体可看函数定义
//sorted(by: <#T##(String, String) throws -> Bool#>)

let rst5 = names.sorted {
    $0.count > $1.count
}
print(rst5)

枚举

import Foundation


/////////////////////////////////
// 枚举
enum Rank:Int{
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    
    func simpleDescription()->String {
        switch self {
        case .Ace: return "ace"
        case .Jack: return "jack"
        case .Queen: return "queen"
        case .King: return "king"
        default:
            return String(self.rawValue)
        }
    }
}

print(Rank.Six.rawValue)
print(Rank.Jack.simpleDescription())



//////////////////////////////
// 1. 简单枚举:保存每周五天工作日并编写description函数
enum WeekDay{
    case Monday
    case Tuesday
    case Wendesday
    case Thursday
    case Friday
    
    func description() {
        switch self {
        case .Monday:
            print("本周工作第一天")
        case .Friday:
            print("就要周末放假了")
        default:
            print("认真工作吧")
        }
    }
}

var day = WeekDay.Monday
print(day)
day.description()
day = .Friday
day.description()
day = .Wendesday
day.description()

结构体

import Foundation

//////////////////////////////////////////
// 1. 结构体:创建学生信息结构体
struct Student {
    var name: String
    var id: String
    var iOS: Int
}

var stu = Student(name: "kangping", id: "20151101xx", iOS: 90)
print(stu)
stu.iOS = 95
print(stu)

import Foundation

// -----------------------------------------------------
// 课堂练习:定义“形状”类并创建对象
// 定义类
class Shape {
    var numberOfSides = 0           // 成员变量(属性)
    func description() {            // 成员函数(方法)
        print("A shape with \(numberOfSides) sides.")
    }
}

//使用类,创建类的对象
var shape = Shape()                 // 使用构造函数(初始化器)创建类的对象实例
shape.numberOfSides = 8
shape.description()



// -----------------------------------------------------
// 2. 值类型与引用类型的区别
struct S {          // 结构体是值类型
    var data:Int = 1
}
var a = S()
var b = a       // 调用拷贝构造函数构造对象b,a与b是两个不同的对象
a.data = 42
print("\(a.data), \(b.data)")

class C {       // 类是引用类型
    var data:Int = -1
}
var x = C()
var y = x       // 不调用拷贝构造函数,x与y指向内存中相同的对象
x.data = 42
print("\(x.data), \(y.data)")



// ---------------------------------------------------------------
// 3. 类的构造:初始化器与反初始化器基本用法
class NamedShape{
    var numberOfSides:Int = 0
    var name:String
    
    init(name:String) {
        self.name = name
    }
    
    deinit {
        print("\(name)'s shape destructed.")
    }
    
    func simpleDescription()->String{
        return "\(name)'s shape with \(numberOfSides) sides."
    }
}

var shape2 = NamedShape(name: "door")
shape2.numberOfSides = 4
print(shape2.simpleDescription())
shape2 = NamedShape(name: "chair")      // 让swift回收对象,调用析构函数




/////////////////////////////////////////////////////////////
// 4. 类的计算属性: 对于三角形类,使用周长计算属性
class EquilaterTriangle{
    var sideLength:Double       // 存储属性,在内存中保存某个值
    
    init(sideLength:Double){
        self.sideLength = sideLength
    }
    
    var perimeter:Double{       // 计算属性,获得或设置等边三角形周长
        get{    // 获取计算属性的值
            return 3.0*sideLength
        }
        set{
            sideLength = newValue/3.0       // newValue是set传递的值
        }
    }
}

var triangle = EquilaterTriangle(sideLength: 3.1)
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)




/////////////////////////////////////////////////////////////
// 5. 类的计算属性: 对于三角形类,使用周长计算属性
class EquilaterTriangle2{
    var sideLength:Double       // 存储属性,在内存中保存某个值
    
    init(sideLength:Double){
        self.sideLength = sideLength
    }
    
    var perimeter:Double{       // 计算属性,获得或设置等边三角形周长
//        get{    // 获取计算属性的值
            return 3.0*sideLength
//        }
//        set{
//            sideLength = newValue/3.0       // newValue是set传递的值
//        }
    }
}

var triangle2 = EquilaterTriangle2(sideLength: 3.1)
print(triangle2.perimeter)
//triangle2.perimeter = 9.9
//print(triangle2.sideLength)



////////////////////////////////////////////////////////////////////
// 6. 属性观察者:使用属性观察者观察等边三角形边长变化
class EquilaterTriangle3{
    var sideLength:Double = 0.0 {
        willSet {
            print("调用观察者willSet,当前值是:\(sideLength),边长新值是:\(newValue)")
        }
        didSet {
            print("调用观察者didSet,当前值是:\(sideLength),边长旧值是:\(oldValue)")
        }
    }
}

var triangle3 = EquilaterTriangle3()
triangle3.sideLength = 10.0
triangle3.sideLength = 20.2



////////////////////////////////////////////////////////////////////
// 7. 类的下标:使用下标返回三角形三边长度
class Triangle{
    var sideLen1 = 3.0
    var sideLen2 = 4.0
    var sideLen3 = 5.0
    
    subscript(sideIndex:Int)->Double{       // 定义类的下标
        switch sideIndex{
        case 1: return sideLen1
        case 2: return sideLen2
        case 3: return sideLen3
        default: return -1
        }
    }
}

var normalTriangle = Triangle()
print(normalTriangle[1])
print(normalTriangle[2])
print(normalTriangle[3])
print(normalTriangle[4])



//////////////////////////////////////////////////////////////////////
// 8. 类的继承:实现正方形类Square,该类继承形状NamedShape类,重写simpleDesription方法,子类中包含求面积方法area
class Square:NamedShape{
    var sideLength:Double
    
    init(sideLength:Double, name:String) {
        self.sideLength = sideLength        // 先初始化子类属性
        super.init(name: name)              // 初始化父类
        numberOfSides = 4                   // 修改父类属性值
    }
    
    func area()->Double{                    // 子类方法
        return sideLength*sideLength
    }
    
    override func simpleDescription() -> String {       // 重写父类方法
        return "A square with sides of length \(sideLength)"
    }
}

let test = Square(sideLength: 5.2, name: "my test square")
print(test.area())
print(test.simpleDescription())



////////////////////////////////
// 9.  便利初始化器
class ClassA{
    let numA:Int
    init(num:Int) {
        numA = num
    }
    convenience init(bigNum:Bool) {
        self.init(num:bigNum ? 10000 : 1)
    }
}

var ObjA = ClassA(bigNum: true)
print(ObjA.numA)

//class ClassB:ClassA{
//    let numB:Int
//    override init(num:Int){
//        numB = num+1
//        super.init(num: num)
//    }
//}
//
//let anObj = ClassB(bigNum: true)
//print(anObj.numA)
//print(anObj.numB)



////////////////////////////////////////
// 10. required keyword
class ClassC{
    let numA:Int
    required init(num:Int) {    // 要求子类有其他初始化器时,必须重写该初始化器
        numA = num
    }
}
class ClassD:ClassC{
    let numB:Int
    let str:String
    required init(num:Int){
        numB = num+1
        self.str = "Hello Kitty"
        super.init(num: num)
    }
    init(str:String, num:Int){
        numB = num+2
        self.str = str
        super.init(num:num)
    }
}
let anObj2 = ClassD(str:"FIFA World Cup 2018 Russia", num:20)
print(anObj2.numA)
print(anObj2.numB)
print(anObj2.str)




/////////////////////////////////////
// 11. 类型检查和转换
class Human{
    
}
class Man:Human{
    
}
class Woman:Human{
    
}
let man = Man()
let woman = Woman()
var arr = [man, woman]

for people in arr{
    if people is Man{
        print("This is man")
    }
    else if people is Woman{
        print("This is woman")
    }
}

for people in arr{
    if ((people as? Man) != nil){
        print("This is man")
    }else if ((people as? Woman) != nil){
        print("This is woman")
    }
}

自己写的代码

print("Hello, World!")

class Shape{
    var numerOfSides = 0
    func description() {
        print("A shape with \(numerOfSides) sides")
    }
}
var s = Shape()
s.numerOfSides = 6
s.description()

struct S {
    var data:Int = 1

}
var s1 = S()
var s2 = s1
s2.data = 2
print("\(s1.data),\(s2.data)")

class C  {
    var data:Int=1
}
var c1 = C()
var c2=c1
c2.data=2
print("\(c1.data),\(c2.data)")

class NameShape {
    var numberOfSides = 0
    var name:String
    init(name:String) {
        self.name=name
    }
    deinit {
        print("\(name)'s shape destructed")
    }
    func simpleDescription() -> String {
        return "\(name)'s shape with \(numberOfSides) sides"
    }
}

var s3 = NameShape(name: "A")
s3.numberOfSides=4
print(s3.simpleDescription())
s3 = NameShape(name:"B")

class EquilaterTriangle{
    var sideLen:Double
    init(sideLen:Double) {
        self.sideLen=sideLen
    }
    var perimeter:Double{
        get{
            return 3.0*sideLen
        }
        set{
            sideLen = newValue/3.0
        }
    }
}
var et = EquilaterTriangle(sideLen: 3.1)
print("\(et.perimeter)")
et.perimeter=9.9
print("\(et.sideLen)")

class EquilaterTriangle2{
    var sideLen:Double = 0.0{
        willSet{
            print("调用观察者willSet,当前值是:\(sideLen),新值是\(newValue)")
        }
        didSet{
            print("调用观察者didSet,当前值是:\(sideLen),旧值是\(oldValue)")
        }
    }
}
var et2 = EquilaterTriangle2()
et2.sideLen=10.0
et2.sideLen=20.0

class Triangle{
    var sideLen1:Double
    var sideLen2:Double
    var sideLen3:Double
    init(sideLen1:Double,sideLen2:Double,sideLen3:Double) {
        self.sideLen1=sideLen1
        self.sideLen2=sideLen2
        self.sideLen3=sideLen3
    }
    subscript( sideIndex:Int) ->Double
    {
        switch sideIndex {
        case 1:return sideLen1
        case 2:return sideLen2
        case 3:return sideLen3
        default:return -1
        }
    }
}
var t = Triangle(sideLen1: 3.0, sideLen2: 4.0, sideLen3: 5.0)
print(t[1])
print(t[2])
print(t[3])

class Square:NameShape{
    var sideLen:Double
    init(sideLen:Double,name: String) {
        self.sideLen=sideLen
        super.init(name: name)
        numberOfSides=4
    }
    func area() -> Double {
        return sideLen*sideLen
    }
    override func simpleDescription() -> String {
        return "A square with side Length \(sideLen)"
    }
}

let square = Square(sideLen: 2.0, name: "C")
print(square.area())
print(square.simpleDescription())

class ClassA {
    let num : Int
    init(num:Int) {
        self.num = num
    }
    convenience init(bigNum:Bool){
        self.init(num: bigNum ? 10000 : 1)
    }
}
var objA = ClassA(bigNum: true)
print(objA.num)

class ClassC{
    var num:Int
    required init(num:Int){
        self.num=num
    }
}
class ClassD: ClassC {
    let numD:Int
    let str:String
    init(str:String,num:Int) {
        self.str=str
        self.numD=num
        super.init(num: num)
    }
    required init(num: Int) {
        self.numD=num+2
        self.str="hello"
        super.init(num: num)
    }

}
let objD=ClassD(str: "FIFA", num: 20)

class Human{
}
class Man:Human{}
class Woman:Human{}
let man=Man()
let woman=Woman()
var arr=[man,woman]
for people in arr{
    if people is Man{
        print("This is man")
    }else if people is Woman{
        print("This is woman")
    }
}

你可能感兴趣的:(Swift,swift)