If you have used objective-C or a language like Ruby, Python, and JavaScript, you may think the struct in SWIFT is as strange as aliens. Class is a traditional structural unit in object-oriented programming languages. Indeed, compared with struct, swift classes support inheritance, (restricted) reflection, destructor, and multiple owners.
Since the structure is so powerful, why do we need to use the structure? It is because of its limited scope of use that the struct is very flexible in building blocks (blocks. In this article, you will learn how struct and other value types greatly improve the definition, flexibility, and readability of the Code.
Value Type and reference type
Struct isValue TypeAnd the class isReference TypeThis line creates an infinite possibility for the architecture due to the slight differences.
Value Type instances are copied when they are assigned values or used as function parameters. Numbers, strings, arrays, dictionaries, enumerations, tuples, and struct are value types. For example:
var a = "Hello"var b = ab.extend(", world")println("a: \(a); b: \(b)") // a: Hello; b: Hello, world
An instance of the reference type (mainly a class) can have multiple owners. When a reference is assigned to a new variable or passed to a function, they all point to the same instance. This is the behavior of the object you are familiar. For example:
var a = UIView()var b = ab.alpha = 0.5println("a: \(a.alpha); b: \(b.alpha)") // a: 0.5; b: 0.5
The difference between the two types does not seem to be big, but selecting a value type or a reference type will bring a big difference to your system architecture.
Cultivate Our intuition
Now that we know the differences between the value type and the reference type behavior, let's discuss the differences in usage.
In the future, in addition to objects, SWIFT may have other reference types. However, in this discussion, we will only use objects as examples of reference types.
We reference objects in code is the same as we reference objects in real life. Programming books often use a real-world metaphor to teach people Object-Oriented Programming: You can createDogClass, and then instantiate it to definefidoThe name of a dog ). If youfidoIt is passed between different parts of the system. They are still talking about the samefido. This makes sense, because if you do have a dog named Fido, you will use it whenever you talk about it.NameTransfer Information-instead of transmitting the dog itself. You may rely on others to know who Fido is. When you use objects, you transmit instances in the system.Name.
The value is the same as the data. If you send a Expense Table to someone else, you do not send a tag that represents the information-you are transmitting the information itself. The message recipient can calculate the sum without communicating with anyone, or write down the fee for future reference. If the message receiver prints the expense records and modifies them, this does not modify your own table.
A value can be a number, a price, or a string-like description. It can be an option in enumeration: Is it because of dinner, travel, or materials? Other values can be included in the specified position, for example,CLLocationCoordinate2DStruct. Or it can be a list of other values.
Fido may run back and forth in its own territory. It may have special behaviors that make it different from other dogs. He may establish relationships with other dogs. You cannot replace Fido with other dogs-your children will find it! However, a Expense Table is independent. Strings and numbers do nothing. They won't be changed in private, no matter how many different methods you use to write6It will always be one6.
This is the greatness of the value type.
Value Type advantages
Objective-C and C have value types, but Swift allows you to use them in scenarios that were previously unavailable. For example, the abstract features of a generic system allow wildcard types to be exchanged between values and reference types. Arrays can be storedIntStorage CapabilityUIView. Enumeration in swift shines even more, because they can now carry some values and methods. Struct can comply with protocols and specified methods.
Swift has enhanced support for value types, which provides a huge opportunity: value types have become a very flexible tool for making code simple. You can use them to extract isolated and foreseeable components from bloated classes. By default, the value type is forced to use or, at least, encouraged to use the attribute to make the work clearer.
In this section, I will describe some situations that encourage the use of Value Type features. It is worth noting that you can also allow objects to include these features, but the language itself determines that you do not need to do so. If you see an object in the code, you will not expect it to have these features; however, if you see a value type, the expectations for these features are reasonable. It is true that not all value types have these attributes -- we will discuss this later -- but this is a reasonable summary.
The value type is stable.
In general, the value type does not have behavior. It is very stable. It stores data and exposes the method for calculating the data. Some methods may change the value type, but the control flow is strictly controlled by the unique owner of the instance.
That's great! This makes it easier to think about the code that will be executed directly called by the only owner.
In contrast, an object may register itself as a timer target. It may receive events from the system. This interaction means that the reference type requires multiple owners. Because the value type can only have one owner and has no destructor, it is not easy for us to write the value type that will affect our side effects.
The value type is isolated.
A typical value type has no implicit dependency on the behavior of any external component. At a glance, the interaction between the value type and its unique owner is much easier than the interaction between the reference type and its unknown number of owners. It is isolated.
If you are getting a reference to a mutable instance, you have an implicit dependency on all other owners of the instance: they may secretly change it at any time.
Value Type is interchangeable
Each time a value type is assigned to a new variable, the value type is replicated, so all these replicas are interchangeable.
You can securely store the values passed to you and then use them in the future.NewUse them with the same value. The only basis for distinguishing this instance from other instances is the data contained in the instance. Swapping also means that no matter how a given value is constructed, if we compare it by =, the same value is equal in any situation.
Therefore, if you use the value type to communicate with the components in the system, you can easily change your component diagram. Do you have a view that depicts the touch sampling sequence? You don't need to touch the view code. By using only one component of the touch sampling sequence, you can compensate for the touch latency. Based on the previous sampling, You can append the prediction that the user's fingers will move to the position, then a new sequence is returned. You can confidently pass the output of another new component to the view-because the view cannot tell the difference.
Writing Unit Tests for value types does not require a fancy mocking framework. You can directlyActiveThe instance creates a value that has no difference. The Touch prediction component mentioned above can easily perform unit tests: predictable value type input, predictable Value Type output, and so on, without side effects.
This is a huge advantage. In a traditional architecture dominated by object behavior, you must test the interaction with the objects being tested and with other parts of the system. It usually means clumsy simulation, or a lot of setup code is added to establish such a relationship. Value types are isolated, stable, and interchangeable, so you can directly construct a value, call a method, and check the output. Simpler testing and wider coverage means easier code modification.
Not all value types have these features
Although the value type structure encourages these features, you can also make the value type violate these features.
Contains the value type of the code that is not called by the owner. It is usually unpredictable and should be avoided in general. For example, a struct constructor may calldispatch_afterTo arrange some work. However, when an instance of the struct is passed to the function, it will be inadvertently repeated because of a copy. The value type should be stable.
The referenced value types are generally not isolated and should be avoided: they carry dependencies on all other owners of that object. These value types are not interchangeable either, because external references may be associated with other parts of the system in a complex way.
Objects
Of course I do not recommend using a stable value type to build everything.
More precisely, objects are also useful because they do not contain the attributes I mentioned above. An object plays an entity role in the system. It has an identity, behavior, and is usually independent.
This behavior is usually complicated and not easy to think about, but some of the details can usually be expressed by simple values and isolated function calls. Those details will not be intertwined with the complex behavior of objects. By separating them, object behavior becomes clearer.
You can think of an object as a thin, imperative layer, which is located on a predictable, pure value layer.
Objects are maintained in States defined by values, but those values are independent of objects being set and operated. Value layer is actually stateless. It is used only to represent and transform data. The meaning of the data as a State may (or may not) be higher, depending on the context of the value.
Objects have side effects like I/O and network, but data, computing, and important decisions finally drive these side effects to exist in the Value Type layer. The object is like a thin film. Through this layer of film, we introduce pure and predictable results into the less pure areas of side effects.
Objects can communicate with other objects, but usually they send values instead of references, unless they do want to create a persistent connection with an external layer that is indispensable.
Summary of value types
Value types allow you to build a clear, simple, and easily tested typical architecture.
Value types and external States usually do not depend on each other or only have few dependencies. Therefore, when you think about them, you only need to consider a few.
Value types are incomposite and reusable because they are interchangeable.
Finally, a value type layer allows you to extract active behavior elements from the stable business logic of the application. The more stable the code, the easier it is to test and modify your system.
References
Boundaries, by Gary Bernhardt, proposes a similar two-level architecture and elaborates on its benefits for concurrency and testing.
Are we there yet ?, By rich Hickey, elaborates on the distinctions between value, State, and identity.
The structure and interpretation of computer programs, by Harry Abelson and Gerald Sussman, too strates just how much can be represented with simple values.
Topic # more articles under 16
Original article a warm welcome to structs and value types
Struct and value type (convert)