Swift 浅谈Struct与Class

   2023-02-08 学习力0
核心提示:讨论Struct与Class之前,我们先来看一个概念:Value Type(值类型),Reference Type(引用类型):1. 值类型的变量直接包含他们的数据,对于值类型都有他们自己的数据副本,因此对一个变量操作不可能影响另一个变量;2. 引用类型的变量存储对他们的数据引用

讨论Struct与Class之前,我们先来看一个概念:Value Type(值类型)Reference Type(引用类型)

1. 值类型的变量直接包含他们的数据,对于值类型都有他们自己的数据副本,因此对一个变量操作不可能影响另一个变量;

2. 引用类型的变量存储对他们的数据引用,因此后者称为对象,因此对一个变量操作可能影响另一个变量所引用的对象。

这就是我们之前博客中提到的深拷贝与浅拷贝,博客传送《iOS 图文并茂的带你了解深拷贝与浅拷贝》,两者的本质区别在于:深拷贝就是内容拷贝,浅拷贝就是指针拷贝

      A. 是否开启新的内存地址

      B. 是否影响内存地址的引用计数

 

讨论Struct与Class之前,我们先做好准备工作,首先分别创建一个Struct:【SNode】 与 Class:【CNode】

struct SNode {
    var Data: Int?
}
class CNode {
    var Data: Int?
}

下面我们通过代码来理解两者都有哪些异同: 

1、property初始化的不同

let snode = SNode(Data: 4) // struct可直接在构造函数中初始化property
print("snode.data:\(String(describing: snode.Data))")


let cnode
= CNode() // class不可直接在构造函数中初始化property
cnode.Data = 5
print("cnode.data:\(String(describing: cnode.Data))")

     打印结果:

snode.data:Optional(4)
cnode.data:Optional(5)

     主要的差別就是 class 在初始化时不能直接把 property 放在 默认的constructor 的参数里,而是需要自己创建一个带参数的constructor, 如:

class CNode {
    var Data: Int?

    init(data: Int) {
        self.Data = data
    }
}
let cnode = CNode.init(data: 5)

 

2、变量赋值方式不同(深浅copy)

// struct
let snode = SNode(Data: 4) var snode1 = snode snode1.Data = 5 print("snode.data:\(String(describing: snode.Data))\n snode1.data:\(String(describing: snode1.Data))")

    打印结果:

snode.data:Optional(4)
snode1.data:Optional(5)

    说明:struct 赋值“=”的时候,会copy一份完整相同的內容给另一個变量 --> 【开辟了新的内存地址】

// class
let cnode = CNode()
cnode.Data = 5
let cnode1 = cnode
cnode1.Data = 6
print("cnode.data:\(String(describing: cnode.Data))\n cnode1.data:\(String(describing: cnode.Data))")

    打印结果:

cnode.data:6
cnode1.data:6

    说明:class 赋值“=”的时候,不会copy一份完整的内容给另一個变量,只是增加了原变量内存地址的引用而已 --> 【没有开辟了新的内存地址】

 

3、immutable 变量

     Swift 语言的特色之一就是可变动内容和不可变内容用 var 和 let 來甄别,如果初始为let的变量再去修改会发生编译错误。

     struct也遵循这一特性

     class不存在这样的问题:从上面的赋值代码能很清楚的看出来。

 

4、mutating function

struct SNode {
    var Data: Int
}

extension SNode {
    mutating func changeData(vaule: Int) {
        self.Data = vaule
    }
}
class CNode {
    var Data: Int = 0
}

extension CNode {
    func changeData(vaule: Int) {
        self.Data = vaule
    }
}

     说明:struct 和 class 的差別是 struct 的 function 要去改变 property 的值的时候要加上 mutating,而 class 不用

 

5、继承

     struct不能继承,class可以继承。

 

6、struct比class更“轻量级”

     struct分配在栈中,class分配在堆中。

 

题外话:Swift 把 Struct 作为数据模型的注意事项

   优点:

   1、安全性:

因为 Struct 是用值类型传递的,它们没有引用计数。

   2、内存:

由于他们没有引用数,他们不会因为循环引用导致内存泄漏。

   3、速度:

 值类型通常来说是以栈的形式分配的,而不是用堆。因此他们比 Class 要快很多!  (http://***.com/a/24243626/596821)

   4、拷贝:

 Objective-C 里拷贝一个对象,你必须选用正确的拷贝类型(深拷贝、浅拷贝),而值类型的拷贝则非常轻松!

   5、线程安全

值类型是自动线程安全的。无论你从哪个线程去访问你的 Struct ,都非常简单。

 

   缺点:

   1、Objective-C

当你的项目的代码是 Swift 和 Objective-C 混合开发时,你会发现在 Objective-C 的代码里无法调用 Swift 的 Struct。因为要在 Objective-C 里调用 Swift 代码的话,对象需要继承于 NSObject。
Struct 不是 Objective-C 的好朋友。

   2、继承

Struct 不能相互继承。

   3、NSUserDefaults

Struct 不能被序列化成 NSData 对象。

 

所以:如果模型较小,并且无需继承、无需储存到 NSUserDefault 或者无需 Objective-C 使用时,建议使用 Struct。

 

知识延伸:为什么访问struct比class快?

“堆”和“栈”并不是数据结构上的Heap跟Stack,而是程序运行中的不同内存空间。栈是程序启动的时候,系统事先分配的,使用过程中,系统不干预;堆是用的时候才向系统申请的,用完了需要交还,这个申请和交还的过程开销相对就比较大了。

栈是编译时分配空间,而堆是动态分配(运行时分配空间),所以栈的速度快。

从两方面来考虑:

      1.分配和释放:堆在分配和释放时都要调用函数(MALLOC,FREE),比如分配时会到堆空间去寻找足够大小的空间(因为多次分配释放后会造成空洞),这些都会花费一定的时间,而栈却不需要这些。

      2.访问时间:访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正得数据,而栈只需访问一次。

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • swift 命令行工具初探
    亲爱的同学们好,今天我们要介绍这么一个东西。相信有过解释型语言(PHP,Ruby,等)使用经验的同学会更加熟悉,就是 Swift 也为我们提供了命令行运行工具,俗称 REPL。好了,我们进入正题,在安装好 Swift 开发环境的机器上,打开命令行,输入 swift 命令,就进
    03-16
  • [Swift]冒泡排序 | Bubble sort
    [Swift]冒泡排序 | Bubble sort
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文
    03-08
  • [Swift] 自定义在 SwiftUI 中实现的可搜索的外观
    [Swift] 自定义在 SwiftUI 中实现的可搜索的外
    首先我找遍了,似乎找不到任何信息......(我遇到了许多根本不起作用的事情......)终于在详细的英文文献中找到了,我会保留下来,希望以后有机会。关于 SwiftUI 中的可搜索searchable是iOS15新增的易于实现的搜索字段。关于这种情况有一个参数placement,您
    03-08
  • [Swift] 检测 SwiftUI ScrollView 中的偏移量
    [Swift] 检测 SwiftUI ScrollView 中的偏移量
    首先你可以用ScrollViewReader做一些可以从iOS14使用的事情。但是,我不能做我想做的事情,所以我想我还能做些什么。再次,可重复使用我尝试过了。执行我将首先发布实现的图像。 (Swift Playgrounds 演示)您可以像这样根据滚动获取坐标。让我们看看实现。1.
    03-08
  • Swift3.0 UICollectionView 删除,拖动
    Swift3.0 UICollectionView 删除,拖动
    UICollectionView实现了一下常见的新闻分类.  附有效果图 近期一直在深入学习swift,实现了CollectionView item的头东与删除,用的都是系统的一些函数方法,看起来比较直观. 第一步:class HotViewController: UIViewController,UICollectionViewDelegate,UICo
    02-09
  • swift -懒加载创建view
     // 只有外界访问到headerView的时候才会去执行闭包, 然后将闭包的返回值赋值给headerView    // 注意: 一定要记住闭包后面需要写上(), 代表执行闭包    //懒加载创建UIView    lazy var headerView: UIView = {        let view = UIView()
    02-09
  • Swift--非常好用的适合局部的代码约束
    // 哪个控件的哪个属性等于(大于、小于)另外一个控件的哪个属性乘以多少再加上多少 eg:let widthContraint = NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLa
    02-09
  • iOS打包framework - Swift完整项目打包Framework,嵌入OC项目使用
    iOS打包framework - Swift完整项目打包Framewor
    场景说明:-之前做的App,使用Swift框架语言,混合编程,内含少部分OC代码。-需要App整体功能打包成静态库,完整移植到另一个App使用,该App使用OC。-所以涉及到一个语言互转的处理,以及一些AppDelegate的代码减除变化。 --------------------------------
    02-09
  • Swift -- 官方文档Swift-Guides的学习笔记
    在经历的一段时间的郁闷之后,我发现感情都是虚伪的,只有代码是真实的(呸)因为看了swift语法之后依然不会用swift,然后我非常作死的跑去看官方文档,就是xcode里自带的help》documentation and API reference其中的swift里的guide这里主要总结一下里面每一
    02-09
  • Swift - 进度条(UIProgressView)的用法
     1,创建进度条1234var progressView=UIProgressView(progressViewStyle:UIProgressViewStyle.Default)progressView.center=self.view.centerprogressView.progress=0.5 //默认进度50%self.view.addSubview(progressView); 2,设置进度,同时有动画效果1p
    02-09
点击排行