本篇內容來自於我在Medium上寫的一篇文章:Swift 語法再讀#1 [Between Struct and Class]
最近在實作的過程中遇到很大觀念上的卡關,因此為了讓實作更加的順利,所以藉由回到官方文件、一些較有公信力的網路資料去重新研究這兩件事情的差異:
這篇文章大抵上會分成兩個重要的部分:
本文將參考至下列文章:
蘋果官方文件:Choosing Between Structures and Classes
https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes
蘋果官方文件:Structures and Classes
https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes
從程式碼的差異探討Struct、Class兩種不同的特性
原則上,我們可以知道上面的幾個文件都共同指出一個Struct、Class的很重要的特性,也就是Struct是以複製(Copy)而聞名、Class是以引用(Reference)而聞名。但是他們看起來都很像,要怎麼知道這是複製還是引用?
或許這要從程式碼開始解釋起:
let stre = 1 + 1
從根本上來判斷兩個物件都在做一樣的事情,都是把結構或是類別實體化,然後也一起做了一件事:把textInClassA的someText屬性指為”TextChange”,這個時候我們在打印出來的文字後發現:
結構(Struct)中的實體,textInStructA、textInStructB居然是兩個不同的東西,打印出兩個不同的內容。
而類別(Class)中的實體,textInClassA、textInClassB則是相同的東西,打印出一樣的內容。
我想這個就要回到本質來討論,Struct的本質是複製,因此在改變textInStructA的someText內容後,其實改變的就只是textStructA本身而已,textStructB並不會因此受到影響,因為它是一個「完全的複製」,從textStructA上複製它的內容。
所以換句話說,textInStructA、textInStructB兩者是兩個不一樣的實體,它們都從同一個結構複製了內容,所以兩者若是互相改動,是不會互相牽絆的。
但在Class裡並不一樣,它是一個參考,而實論為什麼改動textInClassA會牽動整個值的變動?以下是來自於文章的解答:
Class 是參考型別,它會複製一份參考,然後建立一個共享實例。在複製後,兩個變數會共同參照同一份資料的實例,因此調整第二個變數的資料時,也會影響原本的變數。
Class 是參考型別,也就是說,一個 Class 型別的變數不會儲存實際的實例,但會儲存一個參考到記憶體 (heap) 儲存實例的位置。
兩者的複製、參考的不同特性,導致了我們今日在MVC架構中使用Struct、Class兩者上有截然不同的認知。
在蘋果官方的文件中,提到了什麼時候使用Struct、什麼時候使用Class,這個答案基本上是依照Struct、Class本身的本質下去延伸的。
在常見的Model中,Struct會是經常看到的東西,蘋果官網在Choosing Between Structures and Classes 一文中有一些解釋:
為什麼會是這樣呢?
由於Struct的特性是複製,它的原理會相較之下簡單,因為它是複製,所以假若我在ViewController中調用了一個Model中,由Struct定義的物件,那它在ViewController裡面調用時,就會是一個複製的概念,這也是為什麼在MVC架構中,我們經常稱Model是一個資料的「藍圖」,我們會在這個藍圖中確認我們需要哪些東西,然後再由ViewController調用,這樣的好處是我們不會有其他連動的問題,因為Struct是複製的。
然而ViewController作為一個文件,它能不能使用Struct呢?這個答案或許不能直接回答可以或不可以,在常見的做法中,都是以Class作為使用,其理由是參考型別的,也就是說,我們假若實體化了Class的內容,它會是參考原先的Class的實體位址。而反過來說,我們若是使用了Struct的話,則會產生一個現象,就是每次的指派都會產生一個新的實體,這會造成一件事情:混淆。
我們會不知道我們所指派的內容究竟源於何處,因為它是一個複製的實體。但Class則是參考某個遠端的實體,所以就特性來說,文件選擇以Class作為實體化才能發揮繼續存在的功能。
Model可以使用Class嗎?
可以,但相應的必須付出代價:也就是是所有的資料會變成是參考的,但這樣會讓程式的撰寫發生更多偵錯的複雜性,不過在初學者階段可能還不會以Class作為主要撰寫Model的方式。這邊就先不提了。未來遇到的時候會更多深入的討論。
Class的概念就像以前電腦教室上課時那樣,所有的人看到的資料都是來自老師那台電腦,所以我們看到的資料並不是真的那份資料,而是經由傳輸,參考自老師那台的。
Struct則是離線文件的概念,一開始的文件只有老師一個人擁有,但他如果要讓同學修改或填寫的話,必須拷貝一份出去,才能給其他人寫,然後再給老師,老師再決定要不要以修改過的拷貝文件作為取代。
所以,Struct、Class的選用會是一個重要的議題,但大部分的情況下,我們都是以在Model裡作為主要設置,而在ViewController裡則是以Class作為主要的設置,因此構成了MVC架構現在的樣子。
鐵人賽