WWDC 2019 Modern Swift API Design

No Prefixes in Swift0only Frameworks

C and Object-C symbols are global
Swift's module system allows disambiguation
Remember-each source file brings its imports into the same namespace

Values and references
Protocols and generics
Key path member lookup
Property wrappers

Classes

reference Type 相当于OC对象的引用

Structs

values Type 会拷贝整个

Enums

values Type 会拷贝整个

Choosing Reference or Values?

Prefer structs over classes
·Only choose classes when reference semantics are important
Classes can make a good choice when
·You need a reference counting and deinitialization
·The value is held centrally and shared
·Where is a separate notion of "identity" from "equality

RealityKit - Scenes and Entities

Values Types Make Copies of References

拷贝struct时,如果内部有引用类型,那么里面的引用类型只会进行浅拷贝,其他值类型则会进行深拷贝

Value and Reference Semantics
//可以通过这样暴露私有参数的内部参数
private var _texture: Texture

public var is Sparkly: Bool {
  get { _texture.isSparkly }
  set {
    // 检查,深复制
    if !isKnownUniquelyReferenced(&_texture) { _texture = Texture(copying: _texture) }
    _texture.isSparkly = newValue
  }
}

Protocols and Generics

Don't Literally Start With a Protocol

Start with concrete use cases
Discover a need for generic code
Try to compose solutions from existing protocols first
Consider a generic type instead of a protocol

SIMD? Scalar?

太多的协议,会造成编译速度变慢,因为会存在一个表里面

Key Path Member Lookup

Property Wrappers

Capture backing storage property and access policy for re-use

public struct MyType {
  @LateInitialized public var ...
//
}

Provides similar benefits to the built-in lazy
·Eliminates boilerplate
·Document semantics at the point of definition

@property Wrapper
public struct LateInitialized {
  private var storage: Value?
  
  public init() {
    storage = nil
  }

  public var value: Value {
    get {
      guard let value = storage else {
        fatalError("value has not yet been set!")
      }
      return value
    }
    set {
      storage = newValue
    }
  }
}

Using Property Wrappers

Use of property wrappers expand into a stored property and a computed property

public struct MyType {
  @LateInitialized public var text: String
  
  // Compiler-synthesized code...
  var $text: LateInitialized = LateInitialized()
  
  public var text: String {
    get { $text.value }
    
    set { $text.value = newValue }
  }
}
Using the DefensiveCopying Property Wrapper

@DefensiveCopying variables can be initialized in their declaration:

public struct MyType {
  @DefensiveCopying public var path: UIBezierPath = UIBezierPath() 
}

// Defensive Copying

@propertyWrapper

public struct DefensiveCopying {
  private var storage: Value

  public init(initialValue value: Value) {
    storage = value.copy() as! Value
  }

  public var value: Value {
    get { storage }
    set {
      storage = newValue.copy() as! Value
    }
  }
}

可以另外添加一个方法不进行拷贝初始化

extension DefensiveCopying {
  public init(withoutCopying value: Value) {
    storage = value
  }
}

Initializing the backing storage property:

public struct MyType {
  @DefensiveCopying public var path: UIBezierPath
  public init() {
    $path = DefensiveCopying(withoutCopying: UIBezierPath())
  }
}
API Design with Property Wrappers

Property wrappers describe the policy behind your data access Lots of API revolves around data access

@UserDefault(key: "BOOSTER_IGNITED", defaultValue: false)
static var isBoosterIgnited: Bool

@ThreadSpecific var localPool: MemoryPool //单独开一个线程存储,可以安全并且不需要考虑多线程的锁

Property Wrappers in SwiftUI

View data dependencies are expressed using property wrappers

struct SlideViewer: View { 
  @State private var isEditing = false
  @Binding var slide: Slide
  var body: some View {
    VStack {
      Text("Slide #\(slide.number)")
      if isEditing { 
        TextField($slide.title)
      }
      // ...
    } 
  }
}

内部实现

// Property Wrappers & Key Path Member Lookup
@propertyWrapper  @dynamicMemberLookup
public var value: Value {
  public struct Binding {
    get { ... }
    nonmutating set { ... }
}
  public subscript(dynamicMember keyPath: WritableKeyPath) ->Binding { ... } //通过这个可以获取内部变量的@Binding属性
}
slide // Slide instance
slide.title // String instance
$slide // Binding instance
$slide.title // Binding instance 相当于 $slide[dynamicMember: \Slide.title]

Summary

Value semantics vs. reference semantics
Use protocols for code reuse — not classification
Property wrappers reuse computed property definitions

你可能感兴趣的:(WWDC 2019 Modern Swift API Design)