# Day19--从Sruct、Class的本质差异论MVC

本篇内容来自於我在Medium上写的一篇文章:Swift 语法再读#1 [Between Struct and Class]

前言

最近在实作的过程中遇到很大观念上的卡关,因此为了让实作更加的顺利,所以藉由回到官方文件、一些较有公信力的网路资料去重新研究这两件事情的差异:

这篇文章大抵上会分成两个重要的部分:

  1. 从程序码举例Struct、Class的差异
  2. Struct、Class最基本的特质与MVC架构应用上的差异

本文将参考至下列文章:

  1. 苹果官方文件:Choosing Between Structures and Classes
    https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

  2. 苹果官方文件:Structures and Classes

https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

  1. Swift Class vs Struct:设计 Model 时,该用 Struct 还是 Class 呢?
    https://www.appcoda.com.tw/swift-class/

正文

从程序码的差异探讨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两者上有截然不同的认知。

MVC架构中的Struct、Class

在苹果官方的文件中,提到了什麽时候使用Struct、什麽时候使用Class,这个答案基本上是依照Struct、Class本身的本质下去延伸的。
在常见的Model中,Struct会是经常看到的东西,苹果官网在Choosing Between Structures and Classes 一文中有一些解释:

  • Use structures by default. 在默认的情况下使用结构
  • Use classes when you need Objective-C interoperability.在需要使用OC的的时候选用class
  • Use classes when you need to control the identity of the data you’re modeling.当您需要控制正在建模的数据的身份时使用类。
  • Use structures along with protocols to adopt behavior by sharing implementations.使用结构和协议通过共享实现来采用行为。

为什麽会是这样呢?

由於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架构现在的样子。

tags: 铁人赛

<<:  [Java Day23] 5.3. 封装

>>:  第19天~dialog+Menu

.NET Core第3天_使用CLI来创建.NET Core专案_专案架构解析

预设不管是透过visual studio 或者额外下载安装完.NET Core SDK 我们能够利用...

Day 30: 机器学习最终回 网路资源总集合

机器学习最终回 网路资源总集合 那麽也到了我们『Machine Learning With Me ,...

Day11 Sideproject(作品集) from 0 to 1 - docker化前端篇

docker的使用也是一直都想学了 我们是开始满久才开始套用进来的 因为刚开始都觉得这是一个很难的东...

html的开始、让网页出现文字

开启visual studio code并且新增一个档案,将档案储存为html档,接下来在档案内输入...