Access Control
1. In terms of access rights control, Swift provides 5 different access levels (the following is sorted from high to low, and entities refer to content modified by the access level)
- open: Allow access in modules that define entities and other modules, and allow other modules to be inherited and rewrite (open can only be used on classes and class members)
- public: Allow access in modules or other modules that define entities, and does not allow other modules to be inherited or rewrite.
- internal: Only accessed in modules that define entities, not in other modules
- fileprivate: Only allow access in the source file that defines the entity
- Private: Only allow access in closed declarations that define entities
2. Most entities are internal level by default
Access level usage guidelines
1. An entity cannot be defined by an entity with a lower access level, for example
- Variable\Constant Type >= Variable\Constant
- Parameter type, return value type >= function
- Parent class >= child class
- ……
Tuple Type
1. The access interface of tuple type is the lowest in all member types
internal struct Dog {} fileprivate class Person {} //(Dog, Person) access level is fileprivatefileprivate var data1: (Dog, Person) private var data2: (Dog, Person)
Generic Types
1. The access level of a generic type is the access level of the type and the access level of all generic type parameters.
Members, nested types
1. The access level of the type will affect the default access level of the nested type of members (properties, methods, initializers, subscripts).
- Generally speaking, the type is private or fileprivate, so the member\necked type is also private or fileprivate by default.
- Generally speaking, the type is internal or public, so the member\nested type is internal by default.
2. The private defined directly under the global scope is equivalent to fileprivate
private struct Dog { var age: Int = 0 func run() {} } fileprivate struct Person { var dog: Dog = Dog() mutating func walk() { () = 1 } }
3. The member access level of the subclass rewrite must be >= member access level of the parent class
getter and setter
1. Getters and setters automatically receive access levels of their environment by default.
2. You can set a lower access level than getter to limit write permissions.
fileprivate(set) public var num = 10 class Person { private(set) var age = 0 fileprivate(set) public var weight: Int { set {} get { 10 } } internal(set) public subscript(index: Int) -> Int { set {} get { index } } }
Initializer
1. If a public class wants to call the compiled and generated default parameterless initializer in another module, it must explicitly provide the public parameterless initializer.
Because the default initializer of the public class is internal level
2. The required initializer must have the same access level as the class it belongs to.
3. If the structure has the storage instance attribute of private\fileprivate, then its member initializer is also private\fileprivate
Otherwise, the default is internal
Enumerate the case of type
1. You cannot set access level separately for each case of enum
2. Each case automatically receives the access level of enum
The case defined by public enum is also public
protocol
1. The requirements (methods) defined in the protocol automatically receive the access level of the protocol, and the access level cannot be set separately.
The requirements (methods) defined by the public protocol are also public
2. The access level implemented by the protocol must be >= type of access level, or >= protocol access level
Extended
1. If the extension's access level is explicitly set, the members added by the extension will automatically receive the extension's access level.
2. If the extension's access level is not explicitly set, the default access level of the members added by the extension is the same as the members directly defined in the type.
3. You can set access levels for members added to the extension separately
4. The extension cannot be explicitly set for extensions used to comply with the protocol.
5. Extensions in the same file can be written as type declarations similar to multiple parts.
- Declare a private member in the original statement, and can access him in the extension of the same file
- Declare a private member in the extension, and can access it in other extensions of the same file,
Assign the method to var\let
1. Methods can also be assigned to a let or var like a function.
struct Person { var age: Int func run(_ v: Int) { print("func run", age, v) } } var fn: (Person) -> (Int) -> () = (_:) fn(Person(age: 10))(20)
Some supplementary knowledge
CustomStringConvertible
1. Comply with the CustomStringConvertible and CustomDebugStringConvertible protocols, and you can customize the printing strings of the instance.
class Person: CustomStringConvertible, CustomDebugStringConvertible { var age = 0 var description: String { "person_\(age)" } var debugDescription: String { "debug_person_\(age)" } }
2. Print calls the description of the CustomStringConvertible protocol
3. The debugPrint and po call the debugDescription of the CustomDebugStringConvertible protocol
Self
1. Self is generally used as the return value type, which limits that the return value and the method caller must be of the same type (can also be used as parameter type)
2. Self represents the current type
class Person { var age = 1 static var count = 2 func run() { print() // 1 print() // 2 } }
assert (assert)
1. Many programming languages have assertion mechanisms: if the specified conditions are not met, the runtime error will be thrown, and the conditional judgment of the commonly used speech debugging (Debug) stage
2. By default, Swift's assertions will only take effect in debug mode, and will be ignored in release mode.
func divide(_ v1: Int, _ v2: Int) -> Int { assert(v2 != 0, "The divisor cannot be 0") return v1 / v2 }
fatalError
1. If you encounter serious problems and want to end the program run, you can directly use the fatalError function to throw an error (this is an error that cannot be caught through do-catch)
2. If you use the fatalError function, you don’t need to write a return
func test(_ num: Int) -> Int { if num >= 0 { return 1 } fatalError("num cannot be less than 0") }
3. In some methods that have to be implemented but do not want others to call, you can consider using the fatalError function internally.
class Person { required init() {} } class Student: Person { required init() { fatalError("don't call Student init()") } init(score: Int) {} } var stu1 = Student(score: 98) var stu2 = Student()
This is the end of this article about the detailed introduction of Swift Access Control access control and assertions. For more related Swift Access Control content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!