玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
在这些回答中没有注意到的一点是,持有类和结构的变量可以是let,同时仍然允许对对象的属性进行更改,而对于结构则不能这样做。
如果你不希望变量指向另一个对象,但仍然需要修改对象,即在有许多实例变量的情况下,你希望一个接一个地更新,这是很有用的。如果它是一个结构,你必须允许变量被重置为另一个对象使用var,因为在Swift常量值类型正确地允许零突变,而引用类型(类)不这样做。
其他回答
一些好处:
由于不可共享,自动线程安全 由于没有isa和refcount,使用更少的内存(实际上通常是堆栈分配) 方法总是静态分派的,所以可以内联(尽管@final可以为类这样做) 更容易推理(不需要“防御性复制”,这是典型的NSArray, NSString等…)出于与线程安全相同的原因
在这些回答中没有注意到的一点是,持有类和结构的变量可以是let,同时仍然允许对对象的属性进行更改,而对于结构则不能这样做。
如果你不希望变量指向另一个对象,但仍然需要修改对象,即在有许多实例变量的情况下,你希望一个接一个地更新,这是很有用的。如果它是一个结构,你必须允许变量被重置为另一个对象使用var,因为在Swift常量值类型正确地允许零突变,而引用类型(类)不这样做。
根据2015年非常流行的WWDC演讲,Swift中面向协议的编程(视频,文本),Swift提供了许多特性,使得结构在很多情况下比类更好。
如果结构相对较小且可复制,则更可取,因为复制比类中对同一个实例有多个引用要安全得多。当将一个变量传递给多个类和/或多线程环境时,这一点尤其重要。如果你总是可以将变量的副本发送到其他地方,你就不必担心其他地方会改变你下面变量的值。
使用Structs,不太需要担心内存泄漏或多个线程竞相访问/修改变量的单个实例。(对于更有技术头脑的人来说,例外情况是在闭包内捕获结构时,因为它实际上是在捕获实例的引用,除非您显式地将其标记为要复制)。
类也可能变得臃肿,因为一个类只能继承一个超类。这鼓励我们创建巨大的超类,其中包含许多不同的能力,而这些能力之间只有松散的关联。使用协议,特别是使用可以为协议提供实现的协议扩展,允许您消除实现此类行为所需的类。
演讲列出了优先使用类的这些场景:
复制或比较实例没有意义(例如,Window) 实例生命周期与外部效果(例如,TemporaryFile)相关联。 实例只是“接收器”——只写外部状态的管道(例如cgcontext)
这意味着结构应该是默认的,而类应该是备用的。
另一方面,Swift编程语言文档有些矛盾:
Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure. As a general guideline, consider creating a structure when one or more of these conditions apply: The structure’s primary purpose is to encapsulate a few relatively simple data values. It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure. Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced. The structure does not need to inherit properties or behavior from another existing type. Examples of good candidates for structures include: The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. In all other cases, 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.
在这里,它声称我们应该只在特定的情况下默认使用类和使用结构。最后,您需要了解值类型与引用类型的实际含义,然后才能就何时使用结构或类做出明智的决定。此外,请记住,这些概念一直在发展,Swift编程语言文档是在面向协议编程演讲之前编写的。
As struct are value types and you can create the memory very easily which stores into stack.Struct can be easily accessible and after the scope of the work it's easily deallocated from the stack memory through pop from the top of the stack. On the other hand class is a reference type which stores in heap and changes made in one class object will impact to other object as they are tightly coupled and reference type.All members of a structure are public whereas all the members of a class are private.
struct的缺点是不能被继承。
结构vs类
[堆栈vs堆] [值vs参考类型]
结构更可取。但是缺省情况下,Struct并不能解决所有问题。通常你会听说值类型是在堆栈上分配的,但这并不总是正确的。只有局部变量被分配到堆栈上
//simple blocks
struct ValueType {}
class ReferenceType {}
struct StructWithRef {
let ref1 = ReferenceType()
}
class ClassWithRef {
let ref1 = ReferenceType()
}
func foo() {
//simple blocks
let valueType1 = ValueType()
let refType1 = ReferenceType()
//RetainCount
//StructWithRef
let structWithRef1 = StructWithRef()
let structWithRef1Copy = structWithRef1
print("original:", CFGetRetainCount(structWithRef1 as CFTypeRef)) //1
print("ref1:", CFGetRetainCount(structWithRef1.ref1)) //2 (originally 3)
//ClassWithRef
let classWithRef1 = ClassWithRef()
let classWithRef1Copy = classWithRef1
print("original:", CFGetRetainCount(classWithRef1)) //2 (originally 3)
print("ref1:", CFGetRetainCount(classWithRef1.ref1)) //1 (originally 2)
}
*你不应该使用/依赖retainCount,因为它没有提供有用的信息
检查堆栈或堆
在编译过程中SIL(Swift中间语言)可以优化你的代码
swiftc -emit-silgen -<optimization> <file_name>.swift
//e.g.
swiftc -emit-silgen -Onone file.swift
//emit-silgen -> emit-sil(is used in any case)
//-emit-silgen Emit raw SIL file(s)
//-emit-sil Emit canonical SIL file(s)
//optimization: O, Osize, Onone. It is the same as Swift Compiler - Code Generation -> Optimization Level
在那里你可以找到alloc_stack(在堆栈上的分配)和alloc_box(在堆上的分配)
(优化级别(SWIFT_OPTIMIZATION_LEVEL)]
推荐文章
- 如何停止不必要的UIButton动画标题变化?
- 如何使用Swift播放声音?
- 如何解散ViewController在Swift?
- 保存字符串到NSUserDefaults?
- 如何将JSON字符串转换为字典?
- 什么是NSLocalizedString等效在Swift?
- 如何创建一个字符串的格式?
- 获取最顶端的UIViewController
- 使用isKindOfClass与Swift
- SourceKitService终止
- 在TypeScript / Angular中什么时候使用Interface和Model
- 我如何在Swift中解析/创建一个以分数秒UTC时区(ISO 8601, RFC 3339)格式化的日期时间戳?
- 如何使用@Binding变量实现自定义初始化
- Swift设置为Array
- 如何设置回退按钮文本在Swift