使用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)")
值类型用途
使用值类型的情形:
使用==运算符比较实例数据的时候。
想单独复制一份实例数据的时候。
当在多线程环境下操作数据的时候。
使用引用类型(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()
要点
类的初始化
使用 init 来创建一个构造器
子类的定义方法是在它们的类名后面加上父类的名字,用冒号分割
创建类的时候并不需要一个标准的根类,所以可以忽略父类。
子类如果要重写父类的方法,需要用override标记
属性可以有 getter 和 setter,这称之为计算属性
计算属性 (闭包) 不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值
即:计算属性可以根据所设置内容,进行一些修改或计算
构造器 init 执行了三步:
这3个步骤顺序不能调换,必须按照这个流程来进行初始化
类的初始化器有两种, 分别是:
1、Designated Initializer(指定初始化器)
指定初始化器是类的最主要的初始化器
它会将类中所有的属性赋值初始化,并且一路往上调用类的父类的指定初始化器去初始化它们各自引入的属性
类可以有多个指定初始化器,也可只有一个,但必须至少有一个
2、Convenience Initializer(便利初始化器)
1)程序在实际使用过程中,对象和对象的实例变量的值可能不同,可以在 init 方法调用的时候传入一个需要的数据,内部再转换
2)将对象用一些默认值进行初始化来让它们适合某种使用场景
便利构造器是一种快速创建对象的方式
本质上是把初始化方法做了一次封装,方便外界使用
便利初始化器不能被子类重写或从子类中以super的方式被调用
一个类可以没有便利初始化器
初始化器调用规则:
required 关键字
required修饰符只能用于修饰类初始化方法。
当子类含有异于父类的初始化方法时(初始化方法参数类型和数量异于父类),子类必须要实现父类的required初始化方法,并且使用required修饰符而不是override
当子类没有初始化方法时,可以不用实现父类的required方法
最大的好处是可以保证依赖于某个指定初始化方法的便利初始化方法一直可以被使用
可失败构造器
init初始化方法可以通过在init关键字后面加上?或!将其变为可失败初始化方法
表示某对象的初始化过程可能失败,并返回 nil
可失败构造器/初始化方法解决了以前在Swift中只能通过工厂方法捕获构造或初始化失败情况的问题
使用可失败构造器可极大程度的统一Swift中的构造对象语法,消除了构造器与工厂方法之间混乱、重复的冗余语法,使Swift更加简洁。
随着可失败构造器这一特性的加入,Swift将对大多数Cocoa中带NSError参数的工厂初始化方法进行调整,从而加强Swift中构造对象语法的统一性,给开发者带来更好的开发体验
属性观察者
如果不需要计算属性,但是需要在设置一个新值之前或者之后运行代码,可以使用属性观察者:
willSet
didSet
属性观察者类似于触发器,用来监视属性的除初始化之外的属性值变化,当属性值发生改变时可以对此作出响应。
特点:
类型检查和转换
==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")
}
}