存儲屬性和計算屬性
今天討論實例存儲屬性與實例變量,結構體常量與實例屬性,定義計算屬性,setter方法,屬性觀察者
存儲屬性:存儲在類和結構體里的變量和常量。分為實例存儲屬性和類型存儲屬性,實例存儲屬性是指單個的實例,用來保存實例的狀態和數據。類型存儲屬性:屬于類型本身。類,結構體,枚舉都可以定義成類型存儲屬性。枚舉不可以定義成實例存儲屬性,
所有的存儲屬性都必須顯示的指定初始值,可以在定義時或者構造器中指定。
可選類型的存儲屬性是可以不指定初始值的
1.程序為所有的實例存儲屬性指定了初始值,且沒有構造器。則系統會提供2個構造器:一個無參數的構造器和一個初始化所有實例存儲屬性的構造器
2.屬性沒有初始值也沒有構造器,系統提供一個初始化所有屬性的構造器
3.有構造器,則要早構造器中為所有的屬性提供初始值
通過構造器函數完成對存儲屬性的初始化:
//存儲屬性
struct lengthrange{
var start: Int
//定義常量存儲屬性,可以不指定初始值
let length: Int
}
var len = lengthrange(start: 9, length: 3)
print(len.start,len.length)
//定義一個結構體常量與她的實例屬性
struct lengthrange2{
var start: Int
var length: Int
}
let len2 = lengthrange(start: 1, length: 2)//不可以改變實例屬性
延遲存儲屬性:第一次調用的時候才會計算初始值的屬性,用lazy的修飾符
延遲存儲是一種延遲機制,只能聲明成變量。
計算屬性
計算屬性就相當于oc中的getter和setter方法合成的屬性,
計算屬性的格式:
/*
[修飾符]var 計算屬性名:屬性類型{
get {
//get方法執行體,該方法一定要有返回值
}
set(形參名){
set方法執行體,該方法一定不能有返回值
}
*/
屬性觀察者:用來觀察屬性的變化的,為了讓屬性在被賦值的時候獲得執行代碼的機會
1.它可以監聽除了延遲屬性之外的所有存儲屬性(包括類型存儲屬性和實例存儲屬性)
2.可以通過重載的方式為繼承得到的屬性添加屬性觀察者
/*
屬性觀察者:
[修飾符]var 計算屬性名: 屬性類型 = 初始值{
will set(newvalue){
//屬性即將被賦值之前調用的方法
}
didset(oldvalue){
//屬性被賦值完成之后自動調用的方法
}
willset和didset后面的參數都是可以省略的
*/
class user{
var first: String = ""
var last: String = ""
//定義計算屬性
var fullname: String{
//定義計算屬性的getter方法,該方法的返回值有first,last兩個存儲屬性決定
get{
return first + "-" + last
}
//定義計算屬性的setter方法
//該setter方法將負責改變該實例的first,last兩個存儲屬性
set(newvalue){
var names = newvalue.components(separatedBy: "-")
self.first = names[0]
self.last = names[1]
}
}
init (first: String , last: String){
self.first = first
self.last = last
}
}
let s = user(first: "swift", last: "hello")
print(s.fullname)//調用get方法
s.fullname = "hello-swift"http://調用setter方法
print(s.first)
//只讀屬性,不需要set部分,可以省略get和花括號
//屬性觀察者
class person {
//定義存儲屬性
var name: String = "" {
willSet{
if newValue.characters.count>6 || newValue.characters.count < 2 {
print("你設置的人名不符合要求,請重新設置")
} else{
print("人名設置成功")
}
}
didSet{
print("人名設置完成,被修改的原名:\(oldValue)")
}
}
var age : Int = 0{
willSet{
if newValue > 100 || newValue < 0 {
print("設置的年齡\(newValue)不符合要求")
} else{
print("年齡設置成功!")
}
}
didSet{
print("年齡設置完成,被修改的年齡為\(oldValue)")
}
}
}
var p = person()
p.age = 999
p.age = 10//將會調用willset和didset方法
swift面相對象中的方法
在方法中,談論的是方法的所屬性,方法轉換為函數,方法的外部形參名,值類型的可變方法,屬性和方法的統一
1.定義方法需要在枚舉,結構體,類中定義,不能夠獨立的定義
2.方法可以使類型本身,也可以是屬于實例
3.不能獨立使用方法,需用類型或者實例充當調用者
4.枚舉和結構體中的方法用static修飾,類中用class修飾,都屬于類方法。否則屬于實例方法
//將方法轉換成函數
class someclass {
func test() {
print("==test 方法 ==")
}
class func bar(msg: String){
print("== bar 類型方法==,傳入的參數:\(msg)")
}
}
//創建實例
var sc = someclass()
//將sc的test方法分離成函數
var f1 : ()->() = sc.test//不能有(),()標示調用方法,沒有()標示賦值給f1,從而把方法轉變成了函數
//將sc的bar方法分離成函數
var f2:(String) -> Void = someclass.bar
//直接調用函數就等于調用了方法
f1() //等價于sc.text()
f2("swift")
方法的外部形參名
//方法的外部形參名
class person {
var name: String
init(name: String){
self.name = name
}
func eat (food: String , drink: String , cigarette: String){//在方法名的前面添加“_”標示不需要外部參數名
print("\(self.name)吃著\(food),喝著\(drink),抽著\(cigarette)")
}
}
var p = person(name: "tom")
p.eat(food: "烤鴨", drink: "啤酒", cigarette: "雪茄")//swift默認會添加外部參數名,
值類型的可變方法
值類型代表的是結構體或者是枚舉,將mutating放在func之前,即將該方法聲明為可變方法
struct jkrect {
var x: Int
var y: Int
var width: Int
var height: Int
mutating func movebyx(x: Int, y: Int) {
self.x += x
self.y += y
}
}
//創建實例
var rect = jkrect(x: 20, y: 12, width: 200, height: 300)
//調用mutating方法,該方法可以改變rect實例的存儲屬性
rect.movebyx(x: 100, y: 90)
print("rect舉行的左上角的x坐標為:\(rect.x),y\(rect.y)")
//注意:常量類型的結構體,枚舉是不可變的
屬性和方法的統一
1.使用函數類型定義屬性,并將函數或者閉包作為該屬性的初始值,這個屬性就成了方法。
//屬性和方法的統一
func factorial(n: Int) -> Int{
var result = 1
for i in 1...n {
result *= i
}
return result
}
struct somestruct {
var info: () -> Void = {
print("info方法")
}
//將全局函數作為fact存儲屬性的初始值
static var fact: (Int) -> Int = factorial
}
var sc = somestruct()
//調用info方法
sc.info()
//使用閉包對sc對象發的info賦值,相當于重新定義sc的info方法
sc.info = {
print("另外一個閉包")
}
sc.info()
var n = 6
//調用的fact方法,執行的是階乘
print("\(n)的階乘是:\(somestruct.fact(6))")
//使用閉包對somestruct的fact賦值,相當于重新定義somestruct的fact方法
somestruct.fact = {
var result = 1
for i in 1...$0{
result += i
}
return result
}
//再次調用fact方法,執行的是累加
print("\(n)的累加的和")
下標
需要了解下標的用法和下標的重載
1.所有的swift類型(枚舉,類,結構體)都支持下標
2.同一個類型可以定義多個下標值
3.通過下標的形參列表或者返回值的類型來區分不同的下標
4.同一個類型中定義多個不同的下標,被稱為下標重載。
//下標的基本用法
/*
Subscripe(形參列表) -> 下標返回值類型 {
get {
//get方法執行體,該方法一定有返回值
}
set (形參名){
//setter方法執行體,該方法可以沒有返回值
}
}
形參列表:與函數的形參列表的用法基本相同,但是不支持指定外部參數和默認值
下標返回值類型:可以是任何有效的類型
*/
//下標
struct jkrect2 {
var x: Int
var y: Int
var width: Int
var height: Int
//定義下標,指定下標只接受int類型的參數,下標返回類型為int
subscript (index: Int) -> Int{
//get部分
get{
switch(index){
case 0:
return self.x
case 1:
return self.y
case 2:
return self.width
case 3:
return self.height
default:
print("不支持該索引值")
return 0
}
}
//set部分
set{
switch(index){
case 0:
self.x = newValue
case 1:
self.y = newValue
case 2:
self.width = newValue
case 3:
self.height = newValue
default:
print("不支持該索引值")
}
}
}
}
//創建實例
var rect2 = jkrect2(x: 20, y: 12, width: 200, height: 300)
//通過下標進行賦值
rect2[0]=40
rect2[1] = 67
//通過下標訪問rect中的函數
print("rect2矩形的x坐標\(rect2[0])y坐標為 \(rect2[1])")
//省略下標中的set部分即是只讀下標