@propertyWrapper

You can think of it first as a special set of getters and setters: it provides a special box that wraps the type of the original value inside. The property declared by the Property Wrapper is actually stored as a “box” of property Wrapper type, but the compiler does some magic so that it is exposed as the wrapper type.

PropertyWrapper basis

PropertyWrapper Advanced PropertyWrapper has its limitations

private enum Key: String {
    case userId
    case sessionId
}

/// @propertywrapper fixed
@propertyWrapper
struct JNDefaults<T> {
    
    let key: String
    let defaultValue:T
    
    // wrappedValue is a fixed name
    var wrappedValue:T {
        set {
            UserDefaults.standard.setValue(newValue, forKey: key)
        }
        get {
            UserDefaults.standard.value(forKey: key) as? T ?? defaultValue
        }
    }
}

enum GloablSettings {
    
    /// call the custom type before fixing it
    @JNDefaults(key: Key.userId.rawValue, defaultValue: nil)
    static var userId:String?
    
    @JNDefaults(key: Key.sessionId.rawValue, defaultValue: nil)
    static var sessionId: String?
}

/// just make that call and store it in UserDefaults
GloablSettings.userId = "15"
Copy the code

I think this thing code read more to understand, many are fixed writing method, correctly applied to their own actual development, readability and simplicity will improve a lot

@propertyWrapper
struct Trimmed {
    private(set) var value: String = ""

    var wrappedValue: String {
        get { value }
        set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
    }

    init(initialValue: String) {
        self.wrappedValue = initialValue
    }
}
struct Post {
    @Trimmed var title: String
    @Trimmed var body: String
}

let quine = Post(title: " Swift Property Wrappers ", body: "...")
quine.title // "Swift Property Wrappers" (no leading or trailing spaces!)

quine.title = " @propertyWrapper "
quine.title // "@propertyWrapper" (still no leading or trailing spaces!)
Copy the code

fallthrough

Typically, the Switch will execute only one case, and in some cases, the next case will also be executed, so fallthrough can be used

Before using

enum AuthStatus {
    case authorized, suspicious, unauthorized
}
let authStatus: AuthStatus = .unauthorized
switch authStatus {
case .suspicious:
    signOut()
case .unauthorized:
    signIn()
    getLocation()
    getWeather()
case .authorized:
    getLocation()
    getWeather()
}
Copy the code

You can use FallThrough instead. If you add FLlThrough, the next case will be executed

switch authStatus {
case .suspicious:
    signOut()
case .unauthorized:
    signIn()
    fallthrough
case .authorized:
    getLocation()
    getWeather()
}
Copy the code

inout

A parameter is a constant and its value cannot be changed, but in some scenarios you can use inout when you need to change the parameter

struct Article {
    var readers: [String]}var article = Article(readers: [])
func add(reader: String.to article: inout Article) {
    article.readers.append(reader)
    refreshUI()
    storeToCoreData()
}
add(reader: "Dylan", to: &article)
add(reader: "Mike", to: &article)
add(reader: "Jenny", to: &article)
print(article.readers) /// ["Dylan", "Mike", "Jenny"]
Copy the code

indirect

Indirect allows an enum enum type to refer to itself, as in the code below, where an error is reported without an indirect

indirect enum City {
    case boston
    case longIsland
    case newYork(nearBy: [City])}let boston: City = .boston
let longIsland: City = .longIsland
let newYork: City = .newYork(nearBy: [.boston, .longIsland])
Copy the code

associatedtype

Associatedtype allows us to use generics in our protocols

// associatedType CombinableData -> CombinableData as a generic type
/// replace CombinableData with the same type such as Double, such as String
protocol Combinable {
    associatedtype CombinableData
    var dataOne: CombinableData { get set }
    var dataTwo: CombinableData { get set }
    func getCombination(a) -> CombinableData
}
struct NumberCombination: Combinable {
    var dataOne: Double
    var dataTwo: Double
    func getCombination(a) -> Double {
        dataOne + dataTwo
    }
}
struct StringCombination: Combinable {
    var dataOne: String
    var dataTwo: String
    func getCombination(a) -> String {
        dataOne + dataTwo
    }
}
Copy the code

subscript

Subscript allows us to customize subscript methods, i.e. subscript defines a method and accesses it using the [] syntax

extension Array {
    / / / subscript definition
    subscript(from index: Int) -> Element? {
        if index > = 0, index < count {
            return self[index]
        } else {
            return nil}}}let names: [String] = ["Dylan"]
/ / / [] to visit
print(names[from: 2]) // nil
Copy the code

typealias

  1. typealiasIs an alias for a specific type. Type, for exampleInt,Double,UIViewController
// 1 Int -> Money is more readable
struct Bank {
  typealias Money = Int
  private var credit: Money = 0
  mutating func deposit(amount: Money) {
    credit + = amount
  }
  mutating func withdraw(amount: Money) {
    credit - = amount
  }
}
Copy the code
/// 2 Take an alias to support cross-platform
#if os(macOS)
import AppKit
public typealias KFCrossPlatformImage = NSImage
public typealias KFCrossPlatformView = NSView
public typealias KFCrossPlatformColor = NSColor
public typealias KFCrossPlatformImageView = NSImageView
public typealias KFCrossPlatformButton = NSButton
#else
import UIKit
public typealias KFCrossPlatformImage = UIImage
public typealias KFCrossPlatformColor = UIColor
#if !os(watchOS)
public typealias KFCrossPlatformImageView = UIImageView
public typealias KFCrossPlatformView = UIView
public typealias KFCrossPlatformButton = UIButton
#if canImport(TVUIKit)
import TVUIKit
#endif
#else
import WatchKit
#endif
#endif
Copy the code
  1. Alias the closure
typealias SingleImageFetcherSuccess = (UIImage) - >Void

public func onSuccess(_ success: @escaping SingleImageFetcherSuccess) -> Self {
    self.success = success
    return self
}
Copy the code
  1. Aliases for generics are supported. Type aliases allow us to write less code and simplify definitions in code
typealias Handler<In> = (In.HTTPResponse? .Context) - >Void

func handle(success: Handler<Int>? .failure: Handler<Error>? .progress: Handler<Double>?{}Copy the code
struct ComputationResult<T> {
  private var result: T
}

typealias DataResult = ComputationResult<Data>
typealias StringResult = ComputationResult<String>
typealias IntResult = ComputationResult<Int>
Copy the code
  1. Type alias of a tuple
// use generics and tuples to define types instead of having to use structs
typealias Generation<T: Numeric> = (initial: T, seed: T, count: Int, current: T)
// if you define such a type alias, you can actually initialize it as if it were a structure:
let firstGeneration = Generation(initial: 10, seed: 42, count: 0, current: 10)
Copy the code
  1. Combination of agreement
protocol CanRead {}
protocol CanWrite {}
protocol CanAuthorize {}
protocol CanCreateUser {}

typealias Administrator = CanRead & CanWrite & CanAuthorize & CanCreateUser
typealias User = CanRead & CanWrite
typealias Consumer = CanRead
Copy the code
  1. Association types

    Combined with the previous associatedType, it is not difficult to understand

public protocol TransformType {
	associatedtype Object
	associatedtype JSON

	func transformFromJSON(_ value: Any?) -> Object?
	func transformToJSON(_ value: Object?). -> JSON?
}

open class DateTransform: TransformType {
	public typealias Object = Date
	public typealias JSON = Double

	public init(a) {}

	open func transformFromJSON(_ value: Any?) -> Date? {
		if let timeInt = value as? Double {
			return Date(timeIntervalSince1970: TimeInterval(timeInt))
		}

		if let timeStr = value as? String {
			return Date(timeIntervalSince1970: TimeInterval(atof(timeStr)))
		}

		return nil
	}

	open func transformToJSON(_ value: Date?). -> Double? {
		if let date = value {
			return Double(date.timeIntervalSince1970)
		}
		return nil}}Copy the code

operator

  1. Prefix Operators, the preceding operator
/ / custom operator | |
prefix operator ||
/ / | | heel RHS values, the value will be - abs (RHS) operation
prefix func ||(rhs: Int) -> Int {   
   -abs(rhs)
}
let numberOne = -3
let numberTwo = 3
print(||numberOne) // -3
print(||numberTwo) // -3
Copy the code
  1. Infix Operators
infix operator --
func --(lhs: Int.rhs: Int) -> Int {
    lhs - (rhs + rhs)
}
print(5 -- 1) / / 3
print(10 -- 2) / / 6
Copy the code
  1. Postfix Operators
postfix operator ++
postfix func ++(lhs: Int) -> Int {
    lhs + lhs
}
print(2++) / / 4
print(10++) / / 20
Copy the code

dynamic

Indicates that the compiler does not inline or virtualize methods of class members or functions. This means that access to this member is distributed dynamically (instead of making static calls) while using Objective-C

class Person {
  // implicitly indicates the "obj" attribute
  // This is useful for libraries or frameworks that rely on objC-C dark magic
  // For example KVO KVC Swizzling
  dynamic var name:String?
}
Copy the code

unowned

Let instance A in the circular reference not forcibly reference instance B. The premise is that instance B has A longer lifetime than instance A.

class Person  
{  
    var occupation:Job?  
}

// When the Person instance does not exist, the job does not exist. The life cycle of a job depends on the Person holding it.
class Job  
{  
    unowned let employee:Person

    init(with employee:Person)  
    {  
        self.employee = employee  
    }  
}
Copy the code

weak

Instance A in A circular reference is allowed to weakly reference instance B, rather than strongly reference it. Instance B has a shorter lifetime and is released first.

class Person  
{  
    var residence:House?  
}

class House  
{  
    weak var occupant:Person?  
}

var me:Person? = Person(a)var myHome:House? = House()

me!.residence = myHome  
myHome!.occupant = me

me = nil  
myHome!.occupant // myHome equals nil
Copy the code