玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
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的缺点是不能被继承。
其他回答
对于类,您获得继承并通过引用传递,而结构则没有继承并通过值传递。
有很多关于Swift的WWDC会议,其中一个会议详细回答了这个问题。确保你看了这些,因为它会让你更快地跟上语言指南或iBook。
结构是值类型,类是引用类型
值类型比引用类型快 值类型实例在多线程环境中是安全的 多线程可以改变实例,而不必担心 关于竞争条件或死锁 与引用类型不同,值类型没有引用;因此, 就是没有内存泄漏。
在以下情况使用值类型:
你希望副本有独立的状态,数据才会被使用 跨多线程的代码
在以下情况使用引用类型:
您希望创建共享的、可变的状态。
更多的信息也可以在苹果文档中找到
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
额外的信息
Swift值类型保存在堆栈中。在进程中,每个线程都有自己的堆栈空间,因此没有其他线程能够直接访问您的值类型。因此,没有竞争条件、锁、死锁或任何相关的线程同步复杂性。
值类型不需要动态内存分配或引用计数,这两者都是昂贵的操作。同时,值类型上的方法是静态分派的。就性能而言,这为值类型创造了巨大的优势。
作为提醒,这里有一个Swift列表
值类型:
结构体 枚举 元组 基本类型(Int, Double, Bool等) 集合(数组,字符串,字典,集合)
引用类型:
类 任何来自NSObject的东西 函数 关闭
假设我们知道Struct是值类型,Class是引用类型。
如果你不知道值类型和引用类型是什么,那么看看按引用传递和按值传递之间的区别是什么?
根据mikeash的帖子:
... Let's look at some extreme, obvious examples first. Integers are obviously copyable. They should be value types. Network sockets can't be sensibly copied. They should be reference types. Points, as in x, y pairs, are copyable. They should be value types. A controller that represents a disk can't be sensibly copied. That should be a reference type. Some types can be copied but it may not be something you want to happen all the time. This suggests that they should be reference types. For example, a button on the screen can conceptually be copied. The copy will not be quite identical to the original. A click on the copy will not activate the original. The copy will not occupy the same location on the screen. If you pass the button around or put it into a new variable you'll probably want to refer to the original button, and you'd only want to make a copy when it's explicitly requested. That means that your button type should be a reference type. View and window controllers are a similar example. They might be copyable, conceivably, but it's almost never what you'd want to do. They should be reference types. What about model types? You might have a User type representing a user on your system, or a Crime type representing an action taken by a User. These are pretty copyable, so they should probably be value types. However, you probably want updates to a User's Crime made in one place in your program to be visible to other parts of the program. This suggests that your Users should be managed by some sort of user controller which would be a reference type. e.g struct User {} class UserController { var users: [User] func add(user: User) { ... } func remove(userNamed: String) { ... } func ... } Collections are an interesting case. These include things like arrays and dictionaries, as well as strings. Are they copyable? Obviously. Is copying something you want to happen easily and often? That's less clear. Most languages say "no" to this and make their collections reference types. This is true in Objective-C and Java and Python and JavaScript and almost every other language I can think of. (One major exception is C++ with STL collection types, but C++ is the raving lunatic of the language world which does everything strangely.) Swift said "yes," which means that types like Array and Dictionary and String are structs rather than classes. They get copied on assignment, and on passing them as parameters. This is an entirely sensible choice as long as the copy is cheap, which Swift tries very hard to accomplish. ...
我个人不会这样命名我的类。我通常将我的命名为UserManager而不是UserController,但想法是一样的
另外,当你必须重写一个函数的每个实例(即它们没有任何共享功能)时,不要使用类。
所以不是一个类的几个子类。使用几个符合协议的结构体。
使用结构体的另一种合理情况是,当你想对新旧模型进行delta/diff运算时。对于引用类型,你不能开箱即用。对于值类型,突变是不共享的。
在Swift中,引入了一种新的编程模式,称为面向协议编程。
创建型模式:
在swift中,Struct是一种自动克隆的值类型。因此,我们可以免费获得实现原型模式所需的行为。
而类是引用类型,在赋值过程中不会自动克隆。为了实现原型模式,类必须采用NSCopying协议。
浅拷贝只复制指向那些对象的引用,而深拷贝复制对象的引用。
为每种引用类型实现深度复制已成为一项乏味的任务。如果类包含进一步的引用类型,我们必须为每个引用属性实现原型模式。然后我们需要通过实现NSCopying协议复制整个对象图。
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
通过使用结构体和枚举,我们使我们的代码更简单,因为我们不需要实现复制逻辑。
结构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)]