[Swift4] Swift筆記 3.0(初探類與物件)
Swift筆記 3.0
初探類與物件 類,函式,閉包,列舉,結構體
3.1 類定義
類定義 例項化
import Foundation
// 4 類與物件
// 定義 類
class Shape {
var numberOfSides = 0 //成員變數 (屬性)
func desicriotion(){ //成員函式 (方法)
print("A shape with \(numberOfSides) sides.")
}
}
// 建立類物件,使用
var s = Shape()
s.numberOfSides = 6
s.desicriotion()
ps: swift中 類 和 結構體 的區別
結構體不能被繼承,類可以 他們都能擁有方法
結構體 ---- 值型別 類 ---- 引用型別
//swift中 類 和 結構體 的區別 struct S{ var data : Int = 1 } var s1 = S() //結構體物件 var s2 = s1 //呼叫拷貝建構函式物件s2 s2.data = 2 print("\(s1.data),\(s2.data)") //輸出 1,2 class C{ var data :Int = 1 } var c1 = C() //類物件 var c2 = c1 //不呼叫拷貝建構函式,增加引用計數 c2.data = 2 print("\(c1.data),\(c2.data)") //輸出 2,2
3.2 類的 初始化器
入c++,java中的建構函式 或是 構造方法
初始化器 init 來構造 類物件 初始化器沒有返回值 不自定義,會有一個預設初始化器械;若定義了一個就不會有; 反初始化器 (解構函式)deinit 有自帶資源回收機制,一般不考慮析構; ps: ? 【可選 符號】意思是,初始化可以失敗, ! 則表示一定會成功
//初始化器 init 來構造 類物件 //命名的類 class NamedShape { var numberOfSides = 0 var name :String init(name:String){ //建構函式 self.name = name } deinit { //解構函式 絕大情況不需要自己去寫 print("Class NamedShape destructed") } func simpleDescription() -> String { return "\(name)'s shape with \(numberOfSides) sides" } } var shapeUnknow = NamedShape(name:"A") shapeUnknow.numberOfSides = 4 print(shapeUnknow.simpleDescription()) shapeUnknow = NamedShape(name :"new")
3.3 類的屬性
swift中,類有兩種屬性
- 儲存屬性
- 計算屬性
儲存屬性:又由其為常量或變數(var / let)可分 常量儲存屬性 和 變數儲存屬性,作為例項的一部分,即為普通的屬性,不贅述
計算屬性: 它計算一個值,類似於方法的功能,提供了一個處理資料的入口與出口。其實它更像一個方法,通過一些儲存屬性值的使用,計算出來,但當用戶呼叫時又感覺不到他是方法,使用起來和普通屬性沒有區別,即對使用者透明。 另外: 有 getter stter 需要注意 。
//舉例: 等邊三角形 ,屬性周長計算屬性
class EquilaterTriangle{
var sideLen :Double //邊長
init (sideLen : Double){
self.sideLen = sideLen
}
//計算屬性 ,物件並沒有為計算屬性設定空間,需要時,會用其他屬性計算,但對使用者隱藏了使用如同正常屬性
var perimeter: Double { //計算屬性 邊長
get { //讀
return 3.0 * sideLen
}
set{ //寫
sideLen = newValue/3.0
//跟新 sideLen。 newValue是set的引數
}
}
}
var et = EquilaterTriangle(sideLen: 3.1)
print("\(et.perimeter)")
et.perimeter = 9.9
print("\(et.sideLen)")
簡化:
如果只讀,則可去掉set,並且可以去掉關鍵字 get 屬性觀察者。監控屬性的變化 willSet —修改之前呼叫 newValue 引數 didSet —修改之後被呼叫 oldValue 引數
//如果只讀,則可去掉set,並且可以去掉關鍵字 get
//屬性觀察者。監控屬性的變化
//willSet ---修改之前呼叫 newValue 引數
//didSet ---修改之後被呼叫 oldValue 引數
//舉例 :屬性觀察者 觀察變長變化
class EquilarterTriangle {
var sideLen :Double = 0.0{
willSet {
print("呼叫屬性觀察者willSet ,當前值是 \(sideLen),new value is \(newValue)")
}
didSet{
print("呼叫屬性觀察者didlSet ,當前值是 \(sideLen),old value is \(oldValue)")
}
}
}
var et = EquilarterTriangle()
et.sideLen = 10.0
et.sideLen = 20.0
3.4 靜態屬性
//靜態屬性
//儲存與類相關的資料,而不是物件資料 ,比如銀行利率
//static 關鍵字
//形成 類的屬性,類的方法,即該類物件共有
//可以由類名 直接使用,不用建立物件
下標
建立下標,直接用下標去訪問屬性
//下標 subscrip
//舉例: 使用三角形 下標 返回三角形三邊的長度
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 T1 = Triangle(sideLen1: 3.0, sideLen2: 4.0, sideLen3: 5.0)
print(T1[1])
print(T1[2])
print(T1[3])
print(T1[4])
3.5 繼承
正如所有面向物件程式設計思想,繼承是為了解決程式碼重複編寫 如經典例子: 一個 Cat 類 一個 Dog 類 一個 Frog 類… 可能他們都有 屬性:age (年齡) 方法:eat(進食); sleep(睡覺) 那麼沒增加定義一個相似的類,只有重新寫一遍相關程式碼。
這不符合 Smart and Lazy 原則,所以採用 程式碼 Reuse【複用】的基本思路。 我們構造一個 Animal 類,其他的類就好像如同這個類所衍生而來,這個Animal類如同父親一般,我們把它叫做父類,或是超類。而派生而來的叫,派生類或子類。子類直接擁有父類的屬性和方法。就如同繼承一般。
繼承 swift特點
- 類可以繼承其他的類 ,把父親類的資料和方法都構造出來
- “:”表示 繼承 關鍵符 ,前為子類 ,後為父類
- 不需要標準類根
- 子類重寫父類 方法,只需要用 關鍵字 【override】標記
- 單繼承,只能有一個父類
//繼承
子類繼承時構造順序必須是:
//構造器 init 執行三步
//1.設定子類宣告的屬性值
//2.呼叫父類的構造器
//3.改變父類的屬性值,其他工作如呼叫方法,修改父類方法在此過程
//實現一個正方形的類,繼承了形狀【nameShape】類
//重寫simpleDescription 方法
class Square : NamedShape {
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 { //overrie 關鍵字 重寫 父類的方法
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)
//required 關鍵字
//子類有其他初始化器的時候,必須重寫
class C {
var num: Int
required init(num :Int){ //子類有其他初始化器的時候,必須重寫
self.num = num
}
}
class D : C {
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 = D(str: "FIFA", num: 20)
//其他一些知識點
//final
//類 則 不能繼承
//屬性方法 則 不能修改
//is 是否是某一個型別
//as
//Any 任何class的型別
//AnyObject 任何型別 (除了方法型別,函式型別)
//理解型別的判斷
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")
}
if people is Woman{
print("THis is Woman")
}
}
一個綜合的例子;
// 綜合例子:
enum Sex {
case female
case male
}
class Person{
var firstName: String
var lastName: String
var age: Int
var gender :Sex
var fullName: String { //計算屬性
return firstName+lastName
}
required init(firstName:String,lastName:String,age:Int,gender:Sex) {
self.age=age
self.firstName=firstName
self.lastName=lastName
self.gender=gender
}
convenience init(defaultData:Bool)//便利初始化器,呼叫初始化器,必須呼叫指定的構造器
{
self.init(firstName: "Jack", lastName: "Smith", age: 20, gender: Sex.male )
}
func work() {
print("Person \(fullName) is working.")
}
}
class Student: Person {
/*var sideLen : Double
init (sideLen:Double,name:String){
self.sideLen = sideLen //初始化子類的屬性
super.init(name: name) //初始化父類屬性,使用父類的建構函式
numberOfSides = 4 //修改父類的屬性
// 順序很重要
}*/
var StuID : String
var cScore :Int
var cppSore :Int
var dataStruct : Int
init(StuID : String,cScore :Int,cppSore :Int,dataStruct : Int,firstName:String,lastName:String,age:Int,gender:Sex) {
self.cppSore=cppSore
self.cScore=cScore
self.dataStruct = dataStruct
self.StuID = StuID
super.init(firstName:firstName , lastName: lastName, age: age, gender: gender)
}
required init(firstName: String, lastName: String, age: Int, gender: Sex) {
fatalError("init(firstName:lastName:age:gender:) has not been implemented")
}
subscript(sideIndex: Int)->Int{
switch sideIndex{
case 1: return cScore
case 2: return cppSore
case 3: return dataStruct
default : return -1
}
}
}
class Teacher: Person {
override func work() {
print("Student \(fullName) is Learning.")
}
}
var person1 = Person(defaultData: true)
var teacherForIOS = Teacher(firstName: "Doctor", lastName: "Who", age: 40, gender: Sex.male)
var student1 = Student(StuID: "2016110246", cScore: 90, cppSore: 95, dataStruct: 55, firstName: "張", lastName:"飛", age: 20, gender: Sex.male)
person1.work()
teacherForIOS.work()
student1.work()
print(student1[1])
print(student1[2])
print(student1[3])