자세한 내용은 실제 documentation에서 확인가능  https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID28

Advanced Operators

Bitwise Operators

Bitwise NOT OperatorThe bitwise NOT operator (~

Bitwise AND OperatorThe bitwise AND operator (&)

Bitwise OR Operator The bitwise OR operator (|)

Bitwise XOR Operator The bitwise XOR operator, or “exclusive OR operator” (^)

Bitwise Left and Right Shift Operators The bitwise left shift operator (<<) and bitwise right shift operator (>>)

Overflow Operators

  • Overflow addition (&+)
  • Overflow subtraction (&-)
  • Overflow multiplication (&*)

Precedence and Associativity

Operator Methods

Classes and structures can provide their own implementations of existing operators. This is known as overloading the existing operators.

Custom Operators

Swift 4— Access Control – Abhimuralidharan – Medium

(참고자료) access control 에 대한 쉬운설명https://medium.com/@abhimuralidharan/swift-3-0-1-access-control-9e71d641a56c

Access Control

source 화일이나 module안의 특정 코드를 외부에서 사용하는 경우 특정코드의 접근여부를 조정할수 있다. 이 내용에 대한 설명

Access control restricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be accessed and used.

You can assign specific access levels to individual types (classes, structures, and enumerations), as well as to properties, methods, initializers, and subscripts belonging to those types. Protocols can be restricted to a certain context, as can global constants, variables, and functions.

In addition to offering various levels of access control, Swift reduces the need to specify explicit access control levels by providing default access levels for typical scenarios. Indeed, if you are writing a single-target app, you may not need to specify explicit access control levels at all.

NOTE

The various aspects of your code that can have access control applied to them (properties, types, functions, and so on) are referred to as “entities” in the sections below, for brevity. 이 설명서에서 

properties, types, functions 등등을 entities로 부르기로 한다.

Modules and Source Files

Swift’s access control model is based on the concept of modules and source files.

A module is a single unit of code distribution—a framework or application that is built and shipped as a single unit and that can be imported by another module with Swift’s import keyword.

Each build target (such as an app bundle or framework) in Xcode is treated as a separate module in Swift. If you group together aspects of your app’s code as a stand-alone framework—perhaps to encapsulate and reuse that code across multiple applications—then everything you define within that framework will be part of a separate module when it’s imported and used within an app, or when it’s used within another framework.

A source file is a single Swift source code file within a module (in effect, a single file within an app or framework). Although it’s common to define individual types in separate source files, a single source file can contain definitions for multiple types, functions, and so on.

Access Levels

Swift provides five different access levels for entities within your code. These access levels are relative to the source file in which an entity is defined, and also relative to the module that source file belongs to. (access level은 entity가 정의 되어있는 source file, 또 source file이 속해 있는 module에 따라 달라진다.)

  • Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. (entity가 정의 되어있는 module내 모든 source file과 이를 import하고있는 module내 모든 source file에서 접근 가능하다. ) You typically use open or public access when specifying the public interface to a framework. The difference between open and public access is described below.
  • Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure. (entity가 정의 되어있는 모든 source file에서 접근 가능, 그러나 다른 module에서는 접근 불가능)
  • File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.
  • Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.(entity가 정의 되어있는 부분에서만 접근가능하고 extension이 정의된 부분에서만 접근가능)

Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.

Open access applies only to classes and class members, and it differs from public access as follows:

  • Classes with public access, or any more restrictive access level, can be subclassed only within the module where they’re defined.(public, fileprivate, private class의 경우 entity가 정의 되어있는 module내에서만 subclass 가능)
  • Class members with public access, or any more restrictive access level, can be overridden by subclasses only within the module where they’re defined. 

    (public, fileprivate, private class member의 경우 entity가 정의 되어있는 module내에서만 subclass 가능)

  • Open classes can be subclassed within the module where they’re defined, and within any module that imports the module where they’re defined. (open은 entity가 import된 module내에서 subclass가능)
  • Open class members can be overridden by subclasses within the module where they’re defined, and within any module that imports the module where they’re defined.

Guiding Principle of Access Levels

Access levels in Swift follow an overall guiding principle: No entity can be defined in terms of another entity that has a lower (more restrictive) access level.

(entity안에 들어 있는 entity는 외부의 access level보다 더 제한적인 access level이어서는 안된다.)

For example:

  • A public variable can’t be defined as having an internal, file-private, or private type, because the type might not be available everywhere that the public variable is used.
  • A function can’t have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are unavailable to the surrounding code.

Default Access Levels

All entities in your code (with a few specific exceptions, as described later in this chapter) have a default access level of internal if you don’t specify an explicit access level yourself.

Access Levels for Unit Test Targets

When you write an app with a unit test target, the code in your app needs to be made available to that module in order to be tested. By default, only entities marked as open or public are accessible to other modules. However, a unit test target can access any internal entity, if you mark the import declaration for a product module with the @testable attribute and compile that product module with testing enabled.(internal로 지정되었지만 unit test를 위해 @

testable 를 import 선언에 표기하는 경우 test하는 module에서 open,public처럼 접근 가능하다.)


Access Control Syntax

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

class SomeInternalClass {}              // implicitly internal
let someInternalConstant = 0            // implicitly internal

Custom Types

IMPORTANT

A public type defaults to having internal members, not public members. If you want a type member to be public, you must explicitly mark it as such. 

public class SomePublicClass {                  // explicitly public class
   public var somePublicProperty = 0            // explicitly public class member
   var someInternalProperty = 0                 // implicitly internal class member
   fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
   private func somePrivateMethod() {}          // explicitly private class member
}
class SomeInternalClass {                       // implicitly internal class
   var someInternalProperty = 0                 // implicitly internal class member
   fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
   private func somePrivateMethod() {}          // explicitly private class member
}
fileprivate class SomeFilePrivateClass {        // explicitly file-private class
   func someFilePrivateMethod() {}              // implicitly file-private class member
   private func somePrivateMethod() {}          // explicitly private class member
}
private class SomePrivateClass {                // explicitly private class
   func somePrivateMethod() {}                  // implicitly private class member
}

Tuple Types

The access level for a tuple type is the most restrictive access level of all types used in that tuple. For example, if you compose a tuple from two different types, one with internal access and one with private access, the access level for that compound tuple type will be private.

NOTE

Tuple types don’t have a standalone definition in the way that classes, structures, enumerations, and functions do. A tuple type’s access level is deduced automatically when the tuple type is used, and can’t be specified explicitly.

Function Types

The access level for a function type is calculated as the most restrictive access level of the function’s parameter types and return type. You must specify the access level explicitly as part of the function’s definition if the function’s calculated access level doesn’t match the contextual default.

The example below defines a global function called someFunction(), without providing a specific access-level modifier for the function itself. You might expect this function to have the default access level of “internal”, but this isn’t the case. In fact, someFunction() won’t compile as written below:

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
   // function implementation goes here
}

The function’s return type is a tuple type composed from two of the custom classes defined above in Custom Types. One of these classes is defined as internal, and the other is defined as private. Therefore, the overall access level of the compound tuple type is private (the minimum access level of the tuple’s constituent types).

Because the function’s return type is private, you must mark the function’s overall access level with the private modifier for the function declaration to be valid:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
   // function implementation goes here
}

It’s not valid to mark the definition of someFunction() with the public or internal modifiers, or to use the default setting of internal, because public or internal users of the function might not have appropriate access to the private class used in the function’s return type.

Enumeration Types

The individual cases of an enumeration automatically receive the same access level as the enumeration they belong to. You can’t specify a different access level for individual enumeration cases.

In the example below, the CompassPoint enumeration has an explicit access level of public. The enumeration cases north, south, east, and west therefore also have an access level of public:

public enum CompassPoint {
   case north
   case south
   case east
   case west
}

Raw Values and Associated Values

The types used for any raw values or associated values in an enumeration definition must have an access level at least as high as the enumeration’s access level. You can’t use a private type as the raw-value type of an enumeration with an internal access level, for example.

Nested Types

Nested types defined within a private type have an automatic access level of private. Nested types defined within a file-private type have an automatic access level of file private. Nested types defined within a public type or an internal type have an automatic access level of internal. If you want a nested type within a public type to be publicly available, you must explicitly declare the nested type as public.

Subclassing

You can subclass any class that can be accessed in the current access context. A subclass can’t have a higher access level than its superclass—for example, you can’t write a public subclass of an internal superclass. (subclass는 superclass의 access level보다 느슨확대될수없다. 같거나 보다 제한된 level이 되어야 한다.)

In addition, you can override any class member (method, property, initializer, or subscript) that is visible in a certain access context. (superclass에 정해진 level에 따라 subclass는 모든 member에 접근가능하다. member에 정해진 level이아니다.)

An override can make an inherited class member more accessible than its superclass version. In the example below, class A is a public class with a file-private method called someMethod(). Class B is a subclass of A, with a reduced access level of “internal”. Nonetheless, class B provides an override of someMethod() with an access level of “internal”, which is higher than the original implementation of someMethod(): (subclass에서는 superclass보다 제한된 level의 member로 override가 가능하다.)

public class A {
   fileprivate func someMethod() {}
}
internal class B: A {
   override internal func someMethod() {}
}

It’s even valid for a subclass member to call a superclass member that has lower access permissions than the subclass member, as long as the call to the superclass’s member takes place within an allowed access level context (that is, within the same source file as the superclass for a file-private member call, or within the same module as the superclass for an internal member call):

public class A {
   fileprivate func someMethod() {}
}
internal class B: A {
   override internal func someMethod() {
       super.someMethod()
   }
}

Because superclass A and subclass B are defined in the same source file, it’s valid for the B implementation of someMethod() to call super.someMethod().

Constants, Variables, Properties, and Subscripts

A constant, variable, or property can’t be more public than its type. It’s not valid to write a public property with a private type, for example. Similarly, a subscript can’t be more public than either its index type or return type. (constant,variable,property,subscript는 용기이며 그 안에 담길 요소. 요소 type의 access level보다 용기의 level이 느슨해질수 없다.)

If a constant, variable, property, or subscript makes use of a private type, the constant, variable, property, or subscript must also be marked as private:

private var privateInstance = SomePrivateClass()

Getters and Setters

(여기서 말하는 getter,setter는 개발자가 작성한 함수를 말하는것이 아니라 constant,variable,property,subscript에 접근할대 swift내부에서 처리되는 과정을 말한다. )

Getters and setters for constants, variables, properties, and subscripts automatically receive the same access level as the constant, variable, property, or subscript they belong to.

You can give a setter a lower access level than its corresponding getter, to restrict the read-write scope of that variable, property, or subscript. You assign a lower access level by writing fileprivate(set), private(set), or internal(set) before the var or subscript introducer.

NOTE

This rule applies to stored properties as well as computed properties. Even though you don’t write an explicit getter and setter for a stored property, Swift still synthesizes an implicit getter and setter for you to provide access to the stored property’s backing storage. Use fileprivate(set), private(set), and internal(set) to change the access level of this synthesized setter in exactly the same way as for an explicit setter in a computed property.

The example below defines a structure called TrackedString, which keeps track of the number of times a string property is modified:

struct TrackedString {

  // 값을 numberOfEdits에 assign할때에만 private level 적용
   private(set) var numberOfEdits = 0
   var value: String = “” {
       didSet {
           numberOfEdits += 1
       }
   }
}

The TrackedString structure defines a stored string property called value, with an initial value of "" (an empty string). The structure also defines a stored integer property called numberOfEdits, which is used to track the number of times that value is modified. This modification tracking is implemented with a didSet property observer on the value property, which increments numberOfEdits every time the value property is set to a new value.

The TrackedString structure and the value property don’t provide an explicit access-level modifier, and so they both receive the default access level of internal. However, the access level for the numberOfEdits property is marked with a private(set) modifier to indicate that the property’s getter still has the default access level of internal, but the property is settable only from within code that’s part of the TrackedString structure. This enables TrackedString to modify the numberOfEdits property internally, but to present the property as a read-only property when it’s used outside the structure’s definition.

If you create a TrackedString instance and modify its string value a few times, you can see the numberOfEditsproperty value update to match the number of modifications:

var stringToEdit = TrackedString()
stringToEdit.value = “This string will be tracked.”
stringToEdit.value += “ This edit will increment numberOfEdits.”
stringToEdit.value += “ So will this one.”
print(“The number of edits is (stringToEdit.numberOfEdits)”)
// Prints “The number of edits is 3”

Although you can query the current value of the numberOfEdits property from within another source file, you can’t modify the property from another source file. This restriction protects the implementation details of the TrackedString edit-tracking functionality, while still providing convenient access to an aspect of that functionality.

Note that you can assign an explicit access level for both a getter and a setter if required. The example below shows a version of the TrackedString structure in which the structure is defined with an explicit access level of public. The structure’s members (including the numberOfEdits property) therefore have an internal access level by default. You can make the structure’s numberOfEdits property getter public, and its property setter private, by combining the public and private(set) access-level modifiers:

public struct TrackedString {
   public private(set) var numberOfEdits = 0
   public var value: String = “” {
       didSet {
           numberOfEdits += 1
       }
   }
   public init() {}
}

Initializers

Custom initializers can be assigned an access level less than or equal to the type that they initialize. The only exception is for required initializers (as defined in Required Initializers). A required initializer must have the same access level as the class it belongs to. (subclass에서 반드시 implemented되야한다고 명시된 것을 required initializer라고 한다. )

As with function and method parameters, the types of an initializer’s parameters can’t be more private than the initializer’s own access level.

Default Initializers

As described in Default Initializers, Swift automatically provides a default initializer without any arguments for any structure or base class that provides default values for all of its properties and doesn’t provide at least one initializer itself.

A default initializer has the same access level as the type it initializes, unless that type is defined as public. For a type that is defined as public, the default initializer is considered internal. If you want a public type to be initializable with a no-argument initializer when used in another module, you must explicitly provide a public no-argument initializer yourself as part of the type’s definition.

Default Memberwise Initializers for Structure Types

The default memberwise initializer for a structure type is considered private if any of the structure’s stored properties are private. Likewise, if any of the structure’s stored properties are file private, the initializer is file private. Otherwise, the initializer has an access level of internal.

As with the default initializer above, if you want a public structure type to be initializable with a memberwise initializer when used in another module, you must provide a public memberwise initializer yourself as part of the type’s definition.

Protocols

If you want to assign an explicit access level to a protocol type, do so at the point that you define the protocol. This enables you to create protocols that can only be adopted within a certain access context.

The access level of each requirement within a protocol definition is automatically set to the same access level as the protocol. You can’t set a protocol requirement to a different access level than the protocol it supports. This ensures that all of the protocol’s requirements will be visible on any type that adopts the protocol.

NOTE

If you define a public protocol, the protocol’s requirements require a public access level for those requirements when they’re implemented. This behavior is different from other types, where a public type definition implies an access level of internal for the type’s members.(protocol의 경우 protocol 전체에 public access level을 지정하면 그 내부의 요소들도 public을 기본으로가지게 된다. 그러나 다른 type의 경우는 public으로 type전체를 정하더라도 그 내부 요소들은 기본적으로 internal level을 가지게 된다.)

Protocol Inheritance

If you define a new protocol that inherits from an existing protocol, the new protocol can have at most the same access level as the protocol it inherits from. You can’t write a public protocol that inherits from an internal protocol, for example. (inherit하는 protocol은 상부 protocol에서 정해진 access level보다 느스한, 넓은 범위의 access level을 가질수 없다.)

Protocol Conformance

A type can conform to a protocol with a lower access level than the type itself. For example, you can define a public type that can be used in other modules, but whose conformance to an internal protocol can only be used within the internal protocol’s defining module. (protocol을 conform하는 type은 protocol의 access level을 따른다.)

If a type is public, but a protocol it conforms to is internal, the type’s conformance to that protocol is also internal.

When you write or extend a type to conform to a protocol, you must ensure that the type’s implementation of each protocol requirement has at least the same access level as the type’s conformance to that protocol. For example, if a public type conforms to an internal protocol, the type’s implementation of each protocol requirement must be at least “internal”.

NOTE

In Swift, as in Objective-C, protocol conformance is global—it isn’t possible for a type to conform to a protocol in two different ways within the same program.

Extensions

You can extend a class, structure, or enumeration in any access context in which the class, structure, or enumeration is available. Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add have a default access level of internal. If you extend a file-private type, any new type members you add have a default access level of file private. If you extend a private type, any new type members you add have a default access level of private. (

class, structure, enumeration 를 extension하는 경우 기존의

class, structure, enumeration 내부에 정의된 access level을 그대로 따른다. )

Alternatively, you can mark an extension with an explicit access-level modifier (for example, private extension) to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.(

private extension 이렇게 표시함으로 명시적으로 extension내에서 정의된 member의 access level를 정의할수 있다.)

You can’t provide an explicit access-level modifier for an extension if you’re using that extension to add protocol conformance. Instead, the protocol’s own access level is used to provide the default access level for each protocol requirement implementation within the extension.  (extension이 protocol conformance를 더하기 위한 것이라면 명시적으로 access level을 지정할수 없다.)

Private Members in Extensions

Extensions that are in the same file as the class, structure, or enumeration that they extend behave as if the code in the extension had been written as part of the original type’s declaration. As a result, you can:(

class, structure, enumeration 를 extension하는 경우 기존에 정의된 private member라도 extension에서 마치 같은 코드상에 있는 것처럼 접근 가능하다.)

  • Declare a private member in the original declaration, and access that member from extensions in the same file. (private이라도 같은 화일의 extension에서 바로접근 가능)
  • Declare a private member in one extension, and access that member from another extension in the same file. (여러번 extension하더라도 private member를 바로 접근 가능)
  • Declare a private member in an extension, and access that member from the original declaration in the same file. (extension에서 private정의된 member도 본래 type정의 코드에서 바로접근 가능)

This behavior means you can use extensions in the same way to organize your code, whether or not your types have private entities. For example, given the following simple protocol:

protocol SomeProtocol {
   func doSomething()
}

You can use an extension to add protocol conformance, like this:

struct SomeStruct {
   private var privateVariable = 12
}
extension SomeStruct: SomeProtocol {
   func doSomething() {

       // 상부에서 private이라고 정의 되었지만 바로접근 가능
       print(privateVariable)
   }
}

Generics

The access level for a generic type or generic function is the minimum of the access level of the generic type or function itself and the access level of any type constraints on its type parameters.

Type Aliases

Any type aliases you define are treated as distinct types for the purposes of access control. A type alias can have an access level less than or equal to the access level of the type it aliases. For example, a private type alias can alias a private, file-private, internal, public, or open type, but a public type alias can’t alias an internal, file-private, or private type. (

alias되는 경우 기존의 type access level에서 제한된 방향으로 access level이 바뀔수 있다.? )

NOTE

This rule also applies to type aliases for associated types used to satisfy protocol conformances.

What is an optional value in Swift?

Memory Safety


Understanding Conflicting Access to Memory

// A write access to the memory where one is stored.
var one = 1
// A read access from the memory where one is stored.
print(“We’re number (one)!”)

A conflicting access to memory can occur when different parts of your code are trying to access the same location in memory at the same time. 

NOTE

If you’ve written concurrent or multithreaded code, conflicting access to memory might be a familiar problem. However, the conflicting access discussed here can happen on a single thread and doesn’t involve concurrent or multithreaded code.

If you have conflicting access to memory from within a single thread, Swift guarantees that you’ll get an error at either compile time or runtime. For multithreaded code, use Thread Sanitizer to help detect conflicting access across threads.

Characteristics of Memory Access

There are three characteristics of memory access to consider in the context of conflicting access: whether the access is a read or a write, the duration of the access, and the location in memory being accessed. Specifically, a conflict occurs if you have two accesses that meet all of the following conditions:

  • At least one is a write access.
  • They access the same location in memory.
  • Their durations overlap.

there are several ways to access memory, called long-term accesses, that span the execution of other code. The difference between instantaneous access and long-term access is that it’s possible for other code to run after a long-term access starts but before it ends, which is called overlap. A long-term access can overlap with other long-term accesses and instantaneous accesses.

Overlapping accesses appear primarily in code that uses in-out parameters in functions and methods or mutating methods of a structure. The specific kinds of Swift code that use long-term accesses are discussed in the sections below.

Conflicting Access to In-Out Parameters

A function has long-term write access to all of its in-out parameters. The write access for an in-out parameter starts after all of the non-in-out parameters have been evaluated and lasts for the entire duration of that function call. If there are multiple in-out parameters, the write accesses start in the same order as the parameters appear.

One consequence of this long-term write access is that you can’t access the original variable that was passed as in-out, even if scoping rules and access control would otherwise permit it—any access to the original creates a conflict. For example:

var stepSize = 1
func incrementInPlace(_ number: inout Int) {
   number += stepSize
}
incrementInPlace(&stepSize)
// Error: conflicting accesses to stepSize

image

One way to solve this conflict is to make an explicit copy of stepSize:

// Make an explicit copy.
var copyOfStepSize = stepSize
incrementInPlace(&copyOfStepSize)
// Update the original.
stepSize = copyOfStepSize
// stepSize is now 2

Another consequence of long-term write access to in-out parameters is that passing a single variable as the argument for multiple in-out parameters of the same function produces a conflict. For example:

func balance(_ x: inout Int, _ y: inout Int) {
   let sum = x + y
   x = sum / 2
   y = sum – x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)
// Error: Conflicting accesses to playerOneScore

NOTE

Because operators are functions, they can also have long-term accesses to their in-out parameters. For example, if balance(_:_:) was an operator function named <^>, writing playerOneScore <^> playerOneScore would result in the same conflict as balance(&playerOneScore, &playerOneScore).

Conflicting Access to self in Methods

참고) 기본적으로 structure,enumeration의 property는 같은 structure,enumeration내의 method를 통해 수정가능하지 않지만 mutating을 이용가능하게 할수 있다.

A mutating method on a structure has write access to self for the duration of the method call. For example, consider a game where each player has a health amount, which decreases when taking damage, and an energy amount, which decreases when using special abilities.

struct Player {
   var name: String
   var health: Int
   var energy: Int
   
   static let maxHealth = 10
   mutating func restoreHealth() {
       health = Player.maxHealth
   }
}

In the restoreHealth() method above, a write access to self starts at the beginning of the method and lasts until the method returns. In this case, there’s no other code inside restoreHealth() that could have an overlapping access to the properties of a Player instance. The shareHealth(with:) method below takes another Player instance as an in-out parameter, creating the possibility of overlapping accesses.

extension Player {
   mutating func shareHealth(with teammate: inout Player) {
       balance(&teammate.health, &health)
   }
}
var oscar = Player(name: “Oscar”, health: 10, energy: 10)
var maria = Player(name: “Maria”, health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK

In the example above, calling the shareHealth(with:) method for Oscar’s player to share health with Maria’s player doesn’t cause a conflict. There’s a write access to oscar during the method call because oscar is the value of self in a mutating method, and there’s a write access to maria for the same duration because mariawas passed as an in-out parameter. As shown in the figure below, they access different locations in memory. Even though the two write accesses overlap in time, they don’t conflict.

image

However, if you pass oscar as the argument to shareHealth(with:), there’s a conflict:

oscar.shareHealth(with: &oscar)
// Error: conflicting accesses to oscar

The mutating method needs write access to self for the duration of the method, and the in-out parameter needs write access to teammate for the same duration. Within the method, both self and teammate refer to the same location in memory—as shown in the figure below. The two write accesses refer to the same memory and they overlap, producing a conflict.

image

Conflicting Access to Properties

Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value.(structure,tuple,enurmeration의 하나의 부분에 접근하는 경우라도 전체에대한 read,write access가 필요하다.) For example, overlapping write accesses to the elements of a tuple produces a conflict:

var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// Error: conflicting access to properties of playerInformation

In the example above, calling balance(_:_:) on the elements of a tuple produces a conflict because there are overlapping write accesses to playerInformation. Both playerInformation.health and playerInformation.energy are passed as in-out parameters, which means balance(_:_:) needs write access to them for the duration of the function call. In both cases, a write access to the tuple element requires a write access to the entire tuple. This means there are two write accesses to playerInformation with durations that overlap, causing a conflict.

The code below shows that the same error appears for overlapping write accesses to the properties of a structure that’s stored in a global variable.

var holly = Player(name: “Holly”, health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // Error

In practice, most access to the properties of a structure can overlap safely. For example, if the variable holly in the example above is changed to a local variable instead of a global variable, the compiler can prove that overlapping access to stored properties of the structure is safe:

// 함수안에서 정해진 변수이면 이런경우는 각요소에 각자 접근 가능

func someFunction() {
   var oscar = Player(name: “Oscar”, health: 10, energy: 10)
   balance(&oscar.health, &oscar.energy)  // OK
}

In the example above, Oscar’s health and energy are passed as the two in-out parameters to balance(_:_:). The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.

The restriction against overlapping access to properties of a structure isn’t always necessary to preserve memory safety. Memory safety is the desired guarantee, but exclusive access is a stricter requirement than memory safety—which means some code preserves memory safety, even though it violates exclusive access to memory. Swift allows this memory-safe code if the compiler can prove that the nonexclusive access to memory is still safe. Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:

  • You’re accessing only stored properties of an instance, not computed properties or class properties.
  • The structure is the value of a local variable, not a global variable.
  • The structure is either not captured by any closures, or it’s captured only by nonescaping closures.

If the compiler can’t prove the access is safe, it doesn’t allow the access.

Generic Protocols with Associated Type – Bob the Developer

Playing with Swift