Swift2.0 屬性的set get willSet willSet ?!可空屬性

標簽(空格分隔): IOS-Swift


[toc]


簡要說明

名稱 功能
set 計算屬性的賦值方法,設置屬性的時候調用
get 計算屬性的讀取方法,取屬性值得時候調用
willSet(newValue) 監視屬性的方法,在屬性值將要改變的時候調用,參數附帶即將改變的值
didSet(oldValue) 監視屬性的方法,在屬性值改變后調用,參數附帶改變之前的值
? 和 ! 屬性的可空標識符. ?表示可空, !表示強制拆包

set和get

在OC中屬性是由set和get方法來實現的,也就是說在打點調用屬性的時候實際上是對屬性的set和get方法進行調用,通過setget方法來實現對類中一個全局變量的讀寫,即時沒有寫set和get方法這兩個方法也是隱式存在的.下面是OC中屬性的實現原型

//普通方式聲明屬性
@property(nonatomic,copy)NSString * str;
//------------------------------------
xx.h
//內部原理
{
NSString * str;
}

  • (void)setObject:(NSString *)anStr;
  • (NSString *)getStr;
    xx.M
    {
    NSString * _object;
    }
  • (void)setObject:(NSString *)anObject{
    _object = anObject;
    }
  • (NSString *)getObject{
    return _object;
    }

看的出來,OC中得屬性實際上是對類內部的一個全局變量的操作.我們可以通過重寫set和get方法來實現屬性變化的監聽,屬性的隱式修改等等.
而在swift中set和get方法并不是必須得.申明屬性是直接生成一個存儲屬性,并不存在隱式的set和get方法,能夠使用set和get方法的只有計算屬性.計算屬性本身并非一個值,只是一個能夠通過打點調用set和get方法的假屬性,計算屬性并不能儲存任何數據且必須實現get方法

class Object: NSObject {
//聲明一個計算屬性
var age:Int{
get{
print("get");
}
set(newValue){
print("(newValue)")
}
}
}
//下面對這個屬性進行使用
let man = People();
man.age = 10;
print("(man.age)")

輸出結果:

set:10 //設置age的值 觸發set方法并將值傳遞給set方法的參數newValue
get //輸出age的值觸發了get方法
0 //輸出age的值為0

可以看出 首先調用set方法 傳遞設置的值,newValue就是傳遞進來的值,設置完成后接著輸出man.age屬性,觸發了get方法的調用,最后輸出age的值,輸出結果為0,也就是說并沒有將設置的值保存起來.再來觀察一下OC的屬性原理,是不是和這個有點類似,如果在swift中創建一個私有的全局變量來儲存set的值,讀取的時候再返回這樣就不就和OC中一樣了嗎?

private var newAge = 0;
var age:Int{
get{
print("get")
return newAge
}
set(newValue){
newAge = newValue;
print("set:(newValue)")
}
}

輸出結果:

set:10
get
10

好了 這樣就還原了OC中的屬性格式,在這兩個方法中我們可以對屬性的值進行處理,由于swift中默認屬性沒有set和get方法 所以我們無法重寫父類屬性的set和get方法.

willSet和didSet

這兩個方法屬于屬性觀察者.分別在屬性值將要被設置和被設置以后調用.屬于基本屬性的方法,可以重寫父類屬性的這兩個方法實現原有OC中重寫set方法的功能.區別是初始化屬性值的時候不會調用這兩個方法.原理更加類似于通知,所以被成為屬性觀察者.

//創建一個觀察者屬性
var  name:String = "0"{
    willSet(new){
        print("will:\(new)");
    }
    didSet(old){
        print("did:\(old)");
    }
}
//調用
var man = People()
man.name = "sad";
print("\(man.name)");
//輸出結果

輸出結果::

will:sad //將要設置值得時候調用,傳遞將要設置的值
did:0 //設置完畢,傳遞一個設置之前的值
sad //最終的值

測試結果顯示,在第一次屬性初始化為0的時候,觀察者方法并沒有調用,只有外部使用改變name值的時候才調用了觀察者方法.

?和!

可空屬性
: 關鍵點,每次使用 ! 強制解包前都應該判斷下是否為空

在swift中所有的屬性變量默認都不能為空,如果不可避免的可能造成為空屬性.則需要聲明為可空屬性.

var name:string = "王五花" //非空屬性,此屬性不可接受空值
var name:string? //可空屬性,此屬性可以接受空值 我們主要介紹這種

swift中空屬性和OC中的空屬性不同,雖然可以直接使用name == nilname != nil來判斷,但是不可直接使用里面的值進行賦值操作.這里就要說一下這個箱子概念了,當一個屬性為可空的時候,這個屬性被放到一個箱子中,這個箱子只有空和非空兩種狀態,由于屬性是在箱子中的所以我們無法直接使用這個屬性值,需要對箱子進行拆解操作man.name = name!如果不拆箱,這個屬性的類型是箱子的類型.

let man:People = People()
//初始化沒有對name進行賦值
if man.name == nil {
print("空")
}
//對屬性進行賦值
man.name = "wang";
print("沒有進行拆包的值:(man.name)")//沒有使用"!"號進行拆包操作
if man.name != nil {
print("拆包以后的值:(man.name!)")//使用了"!"拆包
}
//使用屬性進行賦值
let str:String = man.name!;
//也可以不拆包使用Optional接受,Optional是一個枚舉變量
let op:Optional = man.name;
print("(op)")
print("str會在接受值的時候強制拆箱操作:(str)")

輸出結果:


沒有進行拆包的值:Optional("wang")
拆包以后的值:wang
Optional("wang")
str會在接受值的時候強制拆箱操作:wang

也就是說,當我們聲明一個可空屬性的時候var name:string? ,這個屬性被一個叫做Optional的箱子裝了起來,這個箱子是允許為空的,使用 man.name == nil 語句來判斷這個箱子里面有沒有值,如果沒有返回空,如果有則不為空.使用man.name = "wang";來向箱子中存放一個值,這個值必須和聲明時的類型相同,當我們需要使用箱子的值的時候如果直接使用那么得到的是Optional值,并非是箱子中的值,所以要想使用箱子中的值需要使用!將箱子打開man.name!使用之前最好判斷下

if let語法
: 使用if let語法可以快速使用可空屬性

普通用法

var str:String?
if str != nil{
var s = str!
pring(s)
}

使用if let語句

var str:String?
if let s = str{//這句的代碼的作用就是當str不為nil時將str解包并賦值給s之后運行{}中的代碼 否則跳過
pring(s)
}

guard語句
: 一個讓人糾結作用的語法糖,很多人都覺得他很簡潔

var str:String?
//這條語句表示在str不為nil的時候 將str的值賦值給s 并跳過{}中的語句 如果str為nil則執行{}中的語句
guard let s = str else{
return
}

還有一種狀態,就是在可空屬性下面還有屬性的時候

class People: NSObject {
var name:Name? //People類的屬性name是個可空的類型
}
class Name: NSObject {
var English:String?//Name類中English也是可空的
var Chinese:String = ""http://Chinese屬性是不可為空的 它有一個默認值.雖然看起來和沒有一樣
}

這時使用name屬性就要格外當心了.雖然系統會提示.

override func viewDidLoad() {
super.viewDidLoad()
let man:People = People()
man.name?.Chinese = "王"http://name屬性此時沒有值,在這里的?表示嘗試調用name屬性 如果不為空則調用name后面的屬性或方法
print("(man.name?.Chinese)");//輸出看看上面的賦值操作會不會成功 結果為:nil 因為name并沒有值,則不會執行?后面的語句 輸出的nil是name的值
man.name = Name()//對name進行初始化
man.name?.Chinese = "王五花"http://再次進行嘗試賦值
print("(man.name?.English)")//打印English屬性,此時English沒有值 對name進行嘗試解包,如果name不為空則使用后面的屬性 結果為:nil 此時打開name輸出的是English的值
print("(man.name!.Chinese)")//打印有值得Chinese屬性,這里使用'!'強制解包,因為我們知道anme已經初始化了.絕對不為空 結果為:王五花 此時強制打開name輸出Chinese的值
man.name?.English = "WangWuhua" //嘗試對English進行賦值 這里也可以用'!'強制解包
print("(man.name?.English)") //嘗試調用name不解包English 結果為:Optional("WangWuhua") 這是我們輸出的是English的值,因為沒有解包操作所以還是Optional類型
print("(man.name?.English!)") //嘗試調用name 強制解包English 結果為:Optional("WangWuhua")此時我們強制解包English 滿以為會輸出WangWuhua,但結果并不是我們想象的那樣,所以推斷'?'并不具備解包能力,只是用來推斷name屬性是否為空,由此決定是否調用name下得屬性
print("(man.name!.English)") //強制解包name 不解包English 結果為:Optional("WangWuhua") 這個比較好理解了.沒有對English解包操作
print("(man.name!.English!)") //強制解包name 強制解包English 結果為:WangWuhua 終于得到想要的結果了.必須要對所有屬性進行強制解包才可以拿到最終值,就好像是一套套娃.我們必須將每個娃娃都打開才能看到最里面的東西
}

總結

  • set和get方法在Swift中沒有默認創建,在基本屬性中并不存在,所以無法重寫父類的非計算屬性的set和get方法.主要作用于對屬性值在寫入和讀取過程中進行計算操作
  • willSet和didSet類似于OC中得KVO,用于監視屬性值的變化
  • 可空屬性,使用 var 屬性名:類名? 這種方式可以聲明一個可空屬性, 這里 ? 表示可空.這樣系統將屬性放到一個箱子中,通過對箱子是否為空的判斷來確定是否有值,如果想要使用箱子中得值必須使用 ! 來強制打開箱子.如果屬性下面還有屬性需要使用 對象.屬性?.屬性A 來對屬性進行一次是否為空得判斷,如果為空則不調用屬性A,如果確定有值可以使用 對象.屬性!.屬性A 來得到屬性A的值 如果屬性A也是可空類型 則需要 對象.屬性!.屬性A! 將每層的箱子都打開才能得到屬性A的值
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容