swift 学习(三)(面向对象基础)
面向对象的基本特征包括:封装,继承,多态
在swift中,类,结构,枚举都具有面向对象特性
但结构和枚举的实例不称为对象,因为结构和枚举不是彻底的面向对象类型,比如他们不能继承。
结构体
struct Point { var x,y: Double } struct Size{ var width, height: Double } struct Rect { var origin : Point var size: Size var area: Double { return size.width * size.height } //结构,枚举中试图修改属性值得方法,计算属性都要加mutating //当声明的是一个常量的时候,这些方法都不可调用 mutating func moveToTheRightBY(dx: Double){ x += dx } } var point = Point(x:0.0,y:0.0) var size = Size(width: 640.0, height: 480.0) var rect =Rect(origin: point, size: size)
类
// 访问权限 public private internal,默认是internal class people{ // 存储属性 持有数据 var 存储实例属性 = "" lazy var 惰性实例存储属性 = UIView() // class let 类存储属性 = 11 不支持 static let 静态存储属性 = 22 // 属性观察者 不能用于惰性属性 var 属性观察者:Int = 0{ willSet(newValue){ } didSet{ } } // class + lazy + final 等同 static // 计算属性 是方法的变种 class var 类计算属性: Int { return 1 } class final var 类计算属性2: Int { return 1 } static var 静态计算属性3:Int{ return 1 } var 实例计算属性:Int{ set(newValue){ } get{ return 1 } } // 下标方法 subscript(number:Int)->String?{ get{ } set(newValue){ } } class func 方法(){} class final func 方法2(){} static func 方法3(){} func 方法4(){} }
lazy 只能修饰存储属性,必须自带默认值,且必须声明为变量,不能使用let,因为常量必须在实例构建时赋值。
是一种将对象的创建或其它高负荷操作延迟到真正需要时才执行的机制。被修饰的字段只有在被调用时才会分配内存,并初始化。也因此,在懒加载属性被调用时,实例的其他非懒加载成员早已存在,所以懒加载属性可以用闭包直接赋值,从而自带逻辑处理。
lazy var players: String[] = { var temporaryPlayers = String[]() temporaryPlayers.append("Mike Buss") return temporaryPlayers }()
属性观察者 willSet,didSet用于观察存储属性值的变化,但不能用于lazy修饰的存储属性
class修饰符不可以用来声明存储属性,只能用于方法和计算属性。表示该成员属所有类的实例公有,作用类似java里的static
static修饰符可以用于存储属性,作用相当于class + final + lazy。静态成员同样是懒加载,且可以被子类继承,但子类调用该成员时,实际上和父类操作的是同一个变量,同一个函数。
class Father{ static var x = 2 } class Son: Father{ } println(Father.x) //2 println(Son.x) //2 Son.x = 3 println(Father.x) //3 println(Son.x) //3
final修饰符的几点使用原则
final
修饰符只能修饰类,表明该类不能被其他类继承,也就是它没资格当父类。final
修饰符也可以修饰类中的属性、方法和下标,但前提是该类并没有被final
修饰过。final
不能修饰结构体和枚举。因为结构体和枚举只能遵循协议(protocol)。虽然协议也可以遵循其他协议,但是它并不能重写遵循的协议的任何成员
枚举
//C中的枚举为了提高可读性,便于维护,而swift中却强大很多 enum Day:Int { case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } var day = Day.Thursday day = .Monday let dayNumber = day.toRaw() //原形(行值) enum Direction { case North, South, East, West } //基于什么类型无关紧要,可以不写 let label = UILabel() label.textAlignment = .Right enum TrainStatus { case OnTime case Delayed(Int) //关联值 init() { self = OnTime } var description :String { switch self { case OnTime :return "准时到达" case Delayed(let minutes): return "延误\(minutes)分钟" } } } var status = TrainStatus () println("列车已\(status.description )") status = .Delayed(43) println("列车已\(status.description )") class Train { enum TrainStatus { case OnTime, Delayed(Int) //关联值 init() { self = OnTime } var description :String { switch self { case OnTime :return "准时到达" case Delayed(let minutes): return "延误\(minutes)分钟" } } } var status = TrainStatus () }
// 枚举应用
// 实现布尔类型 enum myBool { case myTrue case myFalse } extension myBool{ init(){ self = myBool.myFalse } } /// 可以用布尔值 字面量赋值 extension myBool:BooleanLiteralConvertible{ init( booleanLiteral value: Bool){ self = value ? .myTrue : .myFalse } } var aaa:myBool = true var bbb:myBool = true extension myBool:BooleanType{ var boolValue: Bool { return self == .myTrue } } if aaa{ println(11) } /// 可以用任何遵循BooleanType的类型初始化 extension myBool{ init<T : BooleanType>(_ value: T){ if value.boolValue{ self = .myTrue } else{ self = .myFalse } } } aaa == bbb /// 比较 extension myBool:Comparable,Equatable{ } func <(lhs: myBool, rhs: myBool) -> Bool{ switch (lhs,rhs){ case (.myTrue,.myFalse): return true default: return false } } if aaa < bbb{ println(222112) }
// 枚举类中定义了两种条形码,一种是普通的条形码 UPCA ,存储四个 Int 值; // 另一种是二维码 QRCode ,存储一个字符串的值: enum Barcode { case UPCA(Int, Int, Int, Int) case QRCode(String) } // 枚举的值可以有关联值,并不是说这里的枚举值就是函数或闭包, // 在switch中可以提供相应的处理代码。 var productBarcode = Barcode.UPCA(8, 85909, 51226, 3) productBarcode = .QRCode("ABCDEFGHIJKLMNOP") switch productBarcode { case .UPCA(let numberSystem, let manufacturer, let product, let check): println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).") case .QRCode(let productCode): println("QR code: \(productCode).") } // prints "QR code: ABCDEFGHIJKLMNOP." // 如果我们要比较两个枚举变量,比如 code1 == code2 ,需要重载运算符 func ==(a:Barcode, b:Barcode) -> Bool { switch(a) { case let .UPCA(a1,b1,c1,d1): switch(b) { case let .UPCA(a2,b2,c2,d2): return (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2) default: return false } case let .QRCode(a1): switch(b) { case let .QRCode(a2): return a1 == a2 default: return false } } } enum Barcode { case UPCA(Int, Int, Int, Int) case QRCode(String) } var code1 = Barcode.UPCA(8, 85909, 51226, 3) var code2 = Barcode.UPCA(8, 85909, 51226, 4) code1 == code2 // false
// 如果没有相关值是可以直接比较的: enum Numbers: Int { case One = 1, Two, Three, Four, Five } var possibleNum1 = Numbers.Three var possibleNum2 = Numbers.Three println(possibleNum1 == possibleNum2) // true
原始值 - Raw Values
我们可以给枚举类型的成员用默认值填充,比如下面这个例子,成员的类型为 Character :
enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" case CarriageReturn = "\r" }
原始值可以是 String
,Character
,Int
,Float
,但是只有 Int 可以自增。使用 toRaw
可以访问该枚举成员的原始值:
ASCIIControlCharacter.Tab.rawValue // rawValue = \t
也可以用 fromRaw
从原始值转换成枚举成员,注意返回的是 .Some
,因为不一定能转换成功:
var a = ASCIIControlCharacter(rawValue: "\t")
a?.rawValue // {Some "\t"}
遍历
我们可以通过 allValues
遍历枚举类型的所有成员:
enum ProductCategory : String { case Washers = "washers", Dryers = "dryers", Toasters = "toasters" static let allValues = [Washers, Dryers, Toasters] } for category in ProductCategory.allValues{ //Do something }
用处
用好枚举类型可以有效的提高代码的可读性,比如我们在 prepareForSegue
中经常需要对 segue.segueIdentifier
进行比较,如果纯粹的进行字符串比较显得很生硬,不妨在外面套上一层枚举类型,像这样:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { if let identifier = SegueIdentifier.fromRaw(segue.identifier) { switch identifier { case .OtherScreenSegue1: println("Going to other screen 1") case .OtherScreenSegue2: println("Going to other screen 2") case .OtherScreenSegue3: println("Going to other screen 3") default: println("Going somewhere else") } } }
同理,用在 NSNotificationCenter
里。
enum WebQuest{ case success(data:[String:AnyObject],block:()->()) case fail(error:NSError,block:()->()) }