struct用法_iOS开发swift语法梳理:结构体Struct和类Class以及内存分布

1.结构体(Struct)概述

  • Swift中的大多数公开类型都是结构体,而枚举和类只占很小一部分。
  • Bool,Int,Double,Array,String,Dictionary等常见类型都是结构体。
  • 所有的结构体会经过编译器自动生成的一个或者多个可传入成员值的初始化器(initialize,初始化方法,构造器,构造方法),宗旨就是:保证所有的成员变量都有初始值
  • 结构体中的成员可以有默认值。
struct Point {
    var x: Int
    var y: Int = 0
}
var p1 = Point(x: 10,y: 10)
var p2 = Point(x: 10) // 由于y有默认值,所以初始化的时候可以不用初始化y.

2.自定义初始化器

当我们自定义的初始化器,编译器就不会再帮我们自动生成其它的初始化器了。

struct Point {
    var x: Int
    var y: Int = 0
    init(x: Int, y: Int) {
       self.x = x
       self.y = y
    }
}

// 那么下面这样初始化 就会报错
var p = Point(x: 10) 

// 只能通过自定义的初始化器来初始化
var p = Point(x: 10, y: 10)

3.结构体的内存结构

struct Point {
    var x: Int = 0
    var y: Int = 0
    var origin: Bool = false
}

print(MemoryLayout<Point>.size) // 输出17 个字节,表示这个结构体用了17个字节,每个Int类型占8个字节
print(MemoryLayout<Point>.stride) // 输出24 个字节,表示这个结构体被分配了24个字节
print(MemoryLayout<Point>.alignment) // 输出8个 字节,对齐参数: 8个字节

4.类(Class)

  • 类的定义和结构体类似,但是编译器没有为类自动生成可传入成员值的初始化器。
  • 而类中的成员都有初始值,则编译器会自动生成无参的初始化器,而且成员的初始化实际上在这个无参初始化器中完成的。
/***类不会自动生成可传入成员值的初始化器***/
class Point {
    var x: Int = 0
    var y: Int = 0
}

// 那么下面这样初始化 就会报错,因为Class不会自动生成可传入值的初始化器。
var p = Point(x: 10) 
// 而只会生成无参的初始化器,下面的会正常调用
var p = Point()



/***成员没有初始化,无参的初始化器也不会调用成功****/
class Point {
    var x: Int
    var y: Int
}
// 由于成员没有初始化,则下面无参数的初始化器会报错
var p = Point()

5.结构体和类的区别(面试常问)

  • struct是值类型,更轻量,存放于栈区;
  • class是引用类型(指针类型),内容存放于堆区,只在栈内存汇总存放类实例的内存地址;
  • struct无法继承,class可继承。
class Size {
  var width = 1
  var height = 2
}

struct Point {
  var x = 3
  var y = 4
}

func test() {
   var size = Size()
   var point = Point()
}

上述代码内存结构如下,Int和指针地址均分别占8个字节:

251f5eb2466fdad6e3bab8979769719e.png

6.值类型

值类型赋值给var、let或者给函数传参,是直接将所有的内容拷贝一份。产生了全新的内容,如遇深拷贝(deep copy)

struct Point {
  var x: Int
  var y: Int
}

func test() {
  var p1 = Point(x: 10,y: 20)
  var p2 = p1   //由于是深拷贝,这时候p2和p1有各自的内存空间
}
// 内存分布如下图

7820decc1535325a6ec6e5aa4a1cc7cd.png
p2.x = 11
p2.y = 22
// 而此时 p1.x = 10, p1.y = 20, 未变,因为他们有相对独立的内存空间

而在Swift标准库中,为了提升性能,String,Array,Dictionary,Set采用了Copy On Write,当有“写”操作的时候,才会真正的执行拷贝操作。

7.引用类型

引用类型的var, let或者给函数传参,是将内存地址拷贝一份,而这个内存地址指向同一个文件,相当于浅拷贝(shallow copy)。

class Size {
  var width: Int
  var height: Int
  init(width: Int, height: Int) {
    self.width = width
    self.height = height
  }
}


func test() {
  var s1 = Size(width: 10, height: 20)
  var s2 = s1   // s1的内存地址赋给了s2
}

5ac26a447d5343b3d52454c49c9b213c.png
s2.width = 11
s2.height = 22
// 此时s1.width = 11,s1.height = 22,因为s1和s2同用一块堆内存空间。

8.值类型和引用类型的let

// 总结:let类型的值类型不可以改变, 而let类型的的引用类型里面的成员可以改
struct Point {
  var x: Int
  var y: Int
}
class Size {
  var width: Int
  var height: Int
  init(width: Int, height: Int) {
    self.width = width
    self.height = height
  }
}

// 定义一个Point常量
let p = Point(x: 10, y: 20) // p的内存不可以改,即p占的16个字节的栈内存不可以变 
// 给这个常量赋值
p = Point(x: 11,y: 22) // 这句代码直接报错
p.x = 33 // 报错 x的存在p的16个字节的栈里面
p.y = 44 // 报错


let s = Size(width: 10, height: 20) // s的内存不可以改,即s的栈内存8个字节的内存地址不可以变
s = Size(width: 11, height: 22) // 报错,不允许s指向新的内存地址
s.width = 33 // 不报错 可以改内存里面的数据,这些成员的值使存在堆内存的
s.height = 44 // 不报错 可以改内存里面的数据

9.嵌套类型

用法类似于内部类。

// struct中嵌套枚举
struct Poker {
    enum Suit: Character {
      case spades = "♠", hearts = "♥", diamond = "♦", clubs = "♣" 
    }

    enum Rank: Int {
      case two = 2, three, four
      case jack, queen, king , ace 
    }
}

// 访问 一步步点下去就ok
print(Poker.Suit.hearts.rawValue)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值