Swift3.0 - 类和结构体的区别

Swift3.0 - 真的很简单
Swift3.0 - 数据类型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可选值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 对象和类
Swift3.0 - 属性
Swift3.0 - 函数和闭包
Swift3.0 - 初始化和释放
Swift3.0 - 协议protocol
Swift3.0 - 类和结构体的区别
Swift3.0 - 枚举
Swift3.0 - 扩展
Swift3.0 - 下标
Swift3.0 - 泛型
Swift3.0 - 异常错误
Swift3.0 - 断言
Swift3.0 - 自动引用计数(strong,weak,unowned)
Swift3.0 - 检测API
Swift3.0 - 对象的标识
Swift3.0 - 注释
Swift3.0 - 元类型
Swift3.0 - 空间命名
Swift3.0 - 对象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 类簇
Swift3.0 - 动态调用对象(实例)方法
Swift3.0 - 文本输出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 镜像
Swift3.0 - 遇到的坑

必须知道的

  • 共同点
    a.定义存储属性
    b.定义函数
    c.定义下标,使用下表访问自己的值
    d.定义初始化设置自己的初始化状态
    e.扩展自己的功能
    f.实现协议提供某种特定的标准功能

  • 不同点(类有更多功能)
    a.类可以继承,结构体不能继承
    b.类能够在运行时检查和解释类实例的类型
    c.Deinitializers使一个类的实例来释放任何资源分配
    d.类有引用计数,允许对象被多次引用

验证

  • 定义
 // 定义类
class StudentC{

}

// 定义结构体
struct StudentS{

}
  • 定义存储属性
 // 定义类
class StudentC{
  var name:String!
}
// 定义结构体
struct StudentS{
    var name:String 
}

提示:

在类中定义属性必须要注意,如果你定义的存储属性不是可选值类型,必须进行初始化,不然编译会报错,但是结构体不会报错,因为系统默认会给结构体创建初始化方法

  • 定义函数
  // 定义类   
 class StudentC{
    static var des:String = "学生的类"
   var name:String!
    func getName()->String{
        return name
    }

    class func describe()->String{
        return des
    }

    static func getClassDescribe()->String{
        return des
    }
}

// 定义结构体
struct StudentS{
    static var des:String = "学生的结构体"
    var name:String
    static func describe()->String{
        return "这是一个定义学生的类"
    }
}

提示:

类可以使用关键字static class 修饰方法,但是结构体只能使用关键字static修饰

  • 扩展下标
  class StudentC{
    var names:[String] = ["1","2","3","4","5"]
    subscript (index:Int)->String?{
        get{
            if names.count <= index{
                return nil
            }
            return names[index]
        }
    }
}

// 定义结构体
struct StudentS{
    var names:[String] = ["1","2","3","4","5"]
    subscript (index:Int)->String?{
        get{
            if names.count <= index{
                return nil
            }
            return names[index]
        }  
    }
}

// 执行
let student1 = StudentC()
print(student1[8])
  • 初始化
 // 定义类
class StudentC{
    var name:String
    init( name:String) {
        self.name = name
    }
}

// 定义结构体
struct StudentS{
    var name:String
    init(name:String) {
        self.name = name
    }
}
let student1 = StudentC(name: "酷走天涯")
let student2 = StudentS(name: "XUJIE")

提示:

结构体默认会有初始化方法

struct StudentS{
var name:String
}
let student2 = StudentS(name: "xujie")
  • 扩展功能
extension StudentC{
  func describe()->String{
      return "学生" + self.name
  }
}
extension StudentS{
    func describe()->String{
        return "学生" + self.name
    }
   }
  • 实现协议
// 定义一个协议
protocol Capacity{
    func draw() // 协议方法
}
// 定义类
class StudentC:Capacity{
    // 实现协议方法
    internal func draw() {
    }
    var name:String
    init( name:String) {
        self.name = name
    }
}
// 定义结构体
struct StudentS:Capacity{
    // 实现协议方法
    internal func draw() {
    }
    var name:String
}
  • 继承
// 定义基类
class Person{
     var name:String
    init( name:String) {
        self.name = name
    }
}
// 定义类
class StudentC:Person{
    var score:Float
    init( name:String,score:Float) {
        self.score = score
        super.init(name: name)
        self.name = name
    }
}

提示:

结构体不能继承结构体

  • mutating 关键字的作用

结构体和枚举都是值类型,但是默认值类型的对象方法不能修改属性值,但是要修改怎么办呢?就必须在函数前面加mutating

//例子1
protocol Action{
    var myY:Int{ mutating get}
}
struct Point{
    var x:Int
    var y:Int
    // 结构体或者枚举修改值必须在函数前面加mutating
    mutating func modifyX(x:Int){
        self.x = x
    }
      // 注意计算属性,mutating 要加载getter方法前面
    var myY:Int{
        mutating get {
            self.y = self.y*2
            return y
        }
    }
 }
// 例子2
struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}
 // 例子3
enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
       case .high:
            self = .off
        }
      }
    }

提示:

1.计算属性setter方法不用修改属性值不用添加mutating
2.计算属性setter方法中修改属性值的时候,一定要加mutating

  • 检测两个对象地址是不是相同
 class StudentC{
     var name:String
      init( name:String) {
          self.name = name
      }
  }
let student1 = StudentC(name: "xujie")
let student2 = student1
if student1 === student2{
 print("地址相同")
}

运行结果:

地址相同

结论:

类是引用类型,结构体是值类型,不能使用===/!== 判断地址

测试:

// 定义结构体
struct StudentS{
    var name:String
}
let student1 = StudentS(name: "xujie")
var student2 = student1
student2.name = "酷走天涯"
print(student1.name)
print(student2.name)

运行结果:

xujie
酷走天涯

  • Deinitializers使一个类的实例来释放任何资源分配
// 定义类
class StudentC{
   var name:String
    init( name:String) {
            self.name = name
    }
     deinit {
    // 释放资源
    }
}

提示:

结构体没有deinit 方法

高级话题

a. 什么时候用结构体

1.该结构的主要目的是封装几个相对简单的数据值
2.如果你希望你的结构在传递的时候被赋值而不是引用
3.希望结构在传递的时候,内部的属性也被复制而不是引用
4.不需要继承属性或者方法

主要应用场景(只包含非对象类型)

1.定义Size
2.定义范围Range
3.定义坐标XYZ
...

b.什么时候用类

除了上面的场景外,其余都使用类对象。

官方建议:

define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures.

用性能说话

测试1: 循环创建类和结构体

a.执行1亿次类创建

// 定义类
class StudentC{
    var name:String
    init( name:String) {
        self.name = name
    }
}
// 统计时间
let date = Date()
for i in 0...100_000_000{
   let s = StudentC(name: "酷走天涯")
}
 print(Date().timeIntervalSince(date))

运行三次结果:

13.3261250257492
13.3587710261345
13.2861340045929

b.执行10亿次结构体创建

// 定义结构体
struct StudentS{
    var name:String
    init( name:String) {
        self.name = name
    }
}
let date = Date()
for i in 0...1000_000_000{
   let s = StudentS(name: "酷走天涯")
}
print(Date().timeIntervalSince(date))

运行三次结果:

6.93744301795959
7.18747901916504
7.20444202423096

我们上面的属性为基本数据类型,我们将属性改为对象测试一下速度

c.创建10_000_000个对象

class StudentC{
    var date = NSDate()
}
for i in 0...10_000_000{
   let s = StudentS()
}

测试结果:

3.38509398698807
3.4364920258522
3.39519000053406

d.创建10_000_000个结构体实例

struct StudentS{
    var date = NSDate()
}
 for i in 0...10_000_000{
   let s = StudentS()
}

测试结果:

2.04776203632355
2.03975200653076
1.98246997594833

结论:

创建结构体要比创建对象速度快

测试2:创建1000_000 个对象或者结构体放在数组中,查看内存占用率

a.循环创建1000_000个对象

class StudentC{
var name:String
init( name:String) {
    self.name = name
}
}
var students:[StudentC] = []
  // 创建
  for i in 0...1000_000{
 let s = StudentC(name: "酷走天涯")
  students.append(s)
 }

运行结果:

内存占用61.8MB

b.循环创建1000_000个结构体

struct StudentS{
    var name:String
    init( name:String) {
        self.name = name
    }
}
var students:[StudentS] = []
for i in 0...1000_000{
 let s = StudentS(name: "酷走天涯")
    students.append(s)
}

运行结果:

内存占用32.6MB

照样,我们将基本属性改为对象继续测试

c.10_000_000 个对象添加到数组中

class StudentC{
    var date = NSDate()
}
var students:[StudentC] = []
for i in 0...10_000_000{
   let s = StudentC()
    students.append(s)
}

测试结果:

占内存538.7MB

d.10_000_000 个结构体添加到数组中

struct StudentS{
    var date = NSDate()
}
for i in 0...10_000_000{
 let s = StudentS()
students.append(s)
}

测试结构:

占用225.7MB

结论:

创建相同属性的结构体比类更加节省内存

  • 对1_000_000个结构体实体和对象进行排序,测消耗时间
    a.对1_000_000个结构体实体进行排序
 let date = Date()
students.sort { (stu1, stu2) -> Bool in
    return stu1.name > stu2.name
}
print(Date().timeIntervalSince(date))

运行结果:

13.3783949613571
13.6793909668922

b.对1_000_000个对象进行排序

 let date = Date()
students.sort { (stu1, stu2) -> Bool in
    return stu1.name > stu2.name
}
print(Date().timeIntervalSince(date))

运行结果:

6.70881998538971
6.60394102334976

结论: 在数据量比较大的排序中,结构体排序的速度比较慢,因为结构体是值类型,排序的时候,需要大量的赋值运算。而对象只需要交换地址即可。

综合建议:

结构体创建速度,内存占用更小,如果需要使用复杂的运算,这个时候,就需要综合考虑两者的有缺点了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容