类(class)

引用类型:将一个对象赋值给另一个对象时,系统不会对此对象进行拷贝,而会将指向这个对象的指针赋值给另一个对象,当修改其中一个对象的值时,另一个对象的值会随之改变。

结构体(struct)

值类型:将一个对象赋值给另一个对象时,会对此对象进行拷贝,复制出一份副本给另一个对象,在修改其中一个对象的值时,不影响另外一个对象。

不同点:

1.struct属于值类型,class属于引用类型

2.class允许被继承,struct不允许被继承

3.class中的每一个成员变量都需要设置初始值或者设置成可选值,需要手动实现构造函数(constructor)来给每个属性设置初始值,否则会被编译器会报错,而struct中的成员变量可以不设置初始值,编译器会自动生成构造函数(constructor)

struct StructTest {
    var name: String?
    var age: Int?
}

class ClassTest {
    var name: String?
    var age: Int?
    /// 如果不手动实现构造函数,编译器会报错
    init(name: String?, age: Int?) {
        self.name = name
        self.age = age
    }
    init(name: String?, age: Int?) {
        self.name = name
        self.age = age
    }
}

  let structTest = StructTest(name: "abc", age: 10)
  let classTest = ClassTest(name: "xyz", age: 20)
  print("\(String(describing: structTest))")
  print("\(String(describing: classTest.name)), \(String(describing: classTest.age))")

4.class遵守了协议没有实现协议方法会报错,而struct遵守了协议没有实现协议方法不会报错

struct StructTest: Equatable {
    /// 如果实现协议方法,编译器不会报错
//    static func == (lhs: ClassTest, rhs: ClassTest) -> Bool {
//        if lhs.name == rhs.name {
//            return true
//        } else {
//            return false
//        }
//    }
    var name: String?
    var age: Int?
}

class ClassTest: Equatable {
    /// 如果实现协议方法,编译器会报错
    static func == (lhs: ClassTest, rhs: ClassTest) -> Bool {
        if lhs.name == rhs.name {
            return true
        } else {
            return false
        }
    }
    
    var name: String?
    var age: Int?
    /// 如果不手动实现构造函数,编译器会报错
    init(name: String?, age: Int?) {
        self.name = name
        self.age = age
    }
}

        let structTest = StructTest(name: "abc", age: 10)
        let classTest = ClassTest(name: "xyz", age: 20)
        print("\(String(describing: structTest))")
        print("\(String(describing: classTest.name)), \(String(describing: classTest.age))")
        
        let structTest1 = StructTest(name: "efg", age: 10)
        let classTest1 = ClassTest(name: "xyz", age: 30)
        print(structTest == structTest1)
        print(classTest == classTest1)
        // 打印:StructTest(name: Optional("abc"), age: Optional(10))
          //    Optional("xyz"), Optional(20)
          //    false
          //    true

5.NSUserdefaults: struct不能被序列化成NSData对象,无法解档

6.swift和Object-C混合开发时,Object-C无法调用swift的struct, 因为在Object-C调用swift代码,对象需要继承于NSObject

7.swift的class像Object-C类一样,可以使用kvc、kvo、runtime的相关方法,适用于runtime系统。而这些struct不具备

8.struct也不能遵守NSObjectProtocol协议

9.内存分配:struct分配在栈中,class分配在堆中

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

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

从两方面来考虑:
1.分配和释放:堆在分配和释放时都要调用函数(MALLOC,FREE),比如分配时会到堆空间去寻找足够大小的空间(因为多次分配释放后会造成空洞),这些都会花费一定的时间,而栈却不需要这些。
2.访问时间:访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正得数据,而栈只需访问一次。