工作中用到的好技术面试好文iOS-基础

iOS值类型和引用类型的区别

2019-05-06  本文已影响0人  Shaw1211

本文主要引自huxinguang002写的Swift 值类型和引用类型以及# Yarn_
写的【Swift学习】值类型、引用类型 & 堆、栈

一个是值类型(Value types) 一个是引用类型(Reference types)。

    class Person {
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    var var1 = Person(name: "John")

此时,var1在内存中是这样的:


图1.png

创建一个新的变量var2让它等于var1:

var var2 = var1

此时,var1 和 var2 指向了内存中的同一个地方:


图2.jpg

上文我们说class是引用类型,顾名思义,"引用"就是C语言中的指针,指针是一个地址,指向某个内存,因此类的变量实际上是存储了实例的地址,当我们声明一个新的变量var2 = var1时,并没有创建一个新的实例,而是把var1实例的地址赋值给var2,于是就有了图2。
知道了类实例的存储机制,下面这种现象就非常容易理解了:

var1.name = "Jane"

print(var1.name)   // Jane
print(var2.name)   //Jane

我们只改变了变量var1的name属性,发现var2的name属性也发生了变化。原因非常明显,因为var1和var2是共享同一个实例,当使用变量var1修改了其所指向的实例之后,var2对应的实例自然也就被修改了。

struct Person {
    var name: String
}
var var1 = Person(name: "John")

此时,var1中存储的不是指向内存的指针,而是值:


图3.png

创建一个新的实例var2,并赋值为var1:

var var2 = var1

此时,系统将会创建一个新的实例并将var1中的值拷贝一份,如下图所示:


图4.png

因此,当修改var1中的属性时,var2的值是不会发生改变的:

    var1.name = "Jane"
    print(var1.name)   //Jane
    print(var2.name)   //John

可以看到var2还是保持原来的值,因为在执行var2 = var1时,系统拷贝了一个新的实例给var2,那么var1与var2之间是不会相互影响的。
值类型和引用类型有各自的优缺点,我们应该根据具体的需求来选择。

堆和栈是内存中不同的分区,它们与引用类型和值类型有很多的联系。

类和结构体定义语法

struct Location {
    let x: Double
    let y: Double
 
    func distance() -> Double {
        return sqrt((x * x) + (y * y))
    }
}
 
class Person {
    var firstName: String
    var lastName: String
 
    init(firstName: String, lastName: String){
        self.firstName = firstName
        self.lastName = lastName
    }
 
    func fullName() -> String{
        return "\(firstName) \(lastName)"
    }
}

此处分别定义了一个Location结构体以及一个Person类,可以看到它们除了关键字的差别,其他的定义方式基本是一样的。结构体和类都可以有属性和方法。

可以看到上文代码比较明显的差别就是:class含有一个init(::)方法,而struct没有。因为所有结构体会自动生成一个成员逐一构造器,用于初始化新结构体实例中的成员属性,因此我们可以直接声明一个实例并设置其各个属性的初始值:

let location = Location(x: 2, y: 4)

而类是没有默认的成员逐一构造器的,因此,若删除class中的init(::)方法,Xcode将会报错:"Class Person has no initailizers",即Person类中没有构造器。因此我们在创建类的时候,必须创建一个及以上的构造器。当然我们也可以对构造器进行重载(overload),系统将会根据参数的类型和数据自动地调用对应的构造器。当在结构体中手动添加了init(::)方法后,默认的成员逐一构造器将会失效。

结构体与类的异同

类和结构体有很多共同点。共同处在于:

与结构体相比,类还有如下的附加功能:

类和结构体在内存中的实现机制的不同:

类和结构体的使用场景

按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:

举例来说,以下情境中适合使用结构体:

类似于上述情形,我们将使用结构体,在其他多数案例中,我们将定义类,生成它的实例,并通过引用来管理和传递。

上一篇下一篇

猜你喜欢

热点阅读