Swift中类以关键字class开头
1.最基本例子
class Shape { //类名
var numberOfSides = 0 //类属性(全局变量)
func simpleDescription() -> String { //类方法
return "A shape with \(numberOfSides) sides." }
}
2.重写init方法
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) { //重写默认的init方法
//name在init时就赋值,这样设置的属性一般不会在后续代码中修改其值
self.name = name
}
func simpleDescription() -> String {
return "A shape name :\(name) with \(numberOfSides) sides."
}
deinit{ //重写默认的销毁方法(相当于delloc)
}
}
var nameShape = NamedShape(name: "Test Shape")
nameShape.numberOfSides = 5
nameShape.simpleDescription()
3.继承
/*
重写init方法,注意Swift和OC不同。Swift的super.init是确保所有子类的属性都初始化完成后书写的,不像OC基本都是写在最前面。原因是,编辑器在执行子类init的init时会优先判断子类自己能不能被成功创建。如果不行,也就没必要去init父类,这样更加节省资源。
所以在Swift中子类的初始化顺序是:
1.设置子类声明属性的值
2.调用父类的初始化器
3.更改父类中定义的属性值。任何额外的设置工作,如使用方法、getter 或 setter 也可以在这里完成(可选操作)
*/
class Square: NamedShape {
var sideLength: Double
//重写init方法
init(sideLength: Double , name: String) {
self.sideLength = sideLength //先实例化子类变量
super.init(name: name) //父类init
numberOfSides = 4 //父类属性值更改
}
func area() -> Double { //子类方法
return sideLength * sideLength
}
//override 关键字 代表重写
override func simpleDescription() -> String {
return "A square with name: \(name) , numberOfSides:\(numberOfSides) , sides of length \(sideLength)."
}
}
var test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
4.属性关联,get 和 set 的用法
get/set被称为"计算属性",它们不直接存储值,但是可用来操作其他属性值的变化
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double { //闭包
get { //重写perimeter的get方法
return 3.0 * sideLength
}
set { //重写perimeter的set方法
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triagle with sides of length \(sideLength) , perimeter is \(perimeter) ."
}
}
5.属性监视器(willSet/didSet)
如果方法本身不需要计算某个属性,但方法中的属性仍然需要提供在运行之前和设置新值后的代码,可以使用 willSet 和 didSet (属性监视器)。
//TriangleAndSquare类要确保其三角的边长和正方形的边长一样。
class TriangleAndSquare {
var triangle: EquilateralTriangle {
//这个类本身不需要对sideLength进行计算,但它里面的属性需要根据sideLength变化而变化
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
let triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
triangleAndSquare.square.sideLength //输出10
triangleAndSquare.triangle.sideLength //输出10
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
triangleAndSquare.triangle.sideLength //输出50
6.函数、方法、实例方法、类方法
在其他语言中,可能函数和方法是分开来的,相互不包括的,但是在Swift中。方法就是函数的一种。一切使用"func"关键字的为都是函数,在外面的是函数,在类中的就是称他为方法,方法中又分"实例方法"和"类方法"
class Counter {
var count: Int = 0
//对于incrementBy1来说numberOfTimes是外部参数名,times是内部参数名
func incrementBy1(amount: Int, numberOfTimes times: Int) {
count = amount * times
}
//"_"关键字代表可以外部调用时可以省略参数名
func incrementBy2(amount: Int,_ times: Int) {
count = amount * times
}
//类方法加上关键字class,类方法不能使用类中的属性
}
func incrementBy4(var a1: Int,a2: Int) {
a1 = a1 + a2
}
var counter = Counter()
counter.incrementBy1(2, numberOfTimes: 7) //实例方法
counter.incrementBy2(2,7) //实例方法
incrementBy4(1, a2: 2) //函数
7.类属性和类方法
class TestCount {
var testInt:Int = 10 //实例属性
//类属性 类属性中只允许使用计算属性(get\set)
class var baseInt:Int{
return 10 //这个是简写的get,这个属性是只读属性
}
class func incrementBy3(times: Int) ->Int {
return baseInt * times
//return testInt * times //类方法不能调用实例属性
}
}
TestCount.baseInt //调用类属性,类不需要实例化
TestCount.incrementBy3(2) //调用类方法,类不需要实例化
8.下标, 或者叫附属脚本(subscript)。
可以定义在 类/结构体/枚举中,进行快速访问。
/*
//格式:也可以设定set/get(和类方法很相似)
subscript(index:Int) -> Int{
get{
}
set{
}
}
*/
struct Person12{ //定义一个结构体
let baseLength:Int
//结构体在这里可以不写初始化方法,会自动生成
subscript(index:Int) -> Int{ //下标方法,无方法名
return baseLength * index
}
}
var p12 = Person12(baseLength: 10)
p12[3] //直接像访问数组一样访问.
9.可选值
当与可选值一起工作时,你可以在操作前写“?”,类似于方法、属性和下标。如果在“?”之前该值已经是 nil,所有“?”之后的东西都会自动忽略,整个表达式的值就是 nil。否则,可选值是未包装的,所有“?” 之后的均视为未包装值。在这两种情况下,整个表达式的值是一个可选值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
10.lazy关键字
使用lazy(延迟)关键字存储属性: 当使用该属性时才进行初始化, 好处是避免空间浪费
class Person1{
var name = "jack"
// class var height:Int = 10 //错误! 类中不能有全局存储属性的, 只能是计算属性. 见下文说明
}
class Person3{
var name:String = "xuneng" //需要手动初始化
var age:Int = 10
let height = 175
lazy var p1:Person1 = Person1() //延迟关键字, 必须是var
}
var p3 = Person3()
p3.name //通过点语法来访问
p3.age = 11 //设置
print(p3.p1) //这句调用时, p1才进行初始化