cs193p_2021笔记[5]_Property Wrappe

2021-11-08  本文已影响0人  walkerwzy

cs193p_2021_笔记_1
cs193p_2021_笔记_2
cs193p_2021_笔记_3_Animation_Transition
cs193p_2021_笔记_4_Color_Image_Gesture
cs193p_2021_笔记_5_Property Wrapper
cs193p_2021_笔记_6_Persistence
cs193p_2021_笔记_7_Document Architecture
cs193p_2021_笔记_8


Property Wrappers

C#中的Attributes,python中的Decorators, Java的Annonations,类似的设计模式。

即能够分配到堆上,能够通知状态变化和能重绘等,可以理解为语法糖

@Published var emojiArt: EmojiArt = EmojiArt()

// ... is really just this struct ...
struct Published {
    var wrappedValue: EmojiArt
    var projectedValue: Publisher<EmojiArt, Never>  // i.e. $
}

// `projected value`的类型取决于wrapper自己,比如本例就是一个`Publisher`

// 我理解为一个属性和一个广播器

// ... and Swift (approximately) makes these vars available to you ...
var _emojiArt: Published = Published(wrappedValue: EmojiArt()) 
var emojiArt: EmojiArt {
     get { _emojiArt.wrappedValue }
     set { _emojiArt.wrappedValue = newValue }
 }

把get,set直接通过$emojiArt(即projectedValue)来使用

当一个Published值发生变化:

下面列的几种Property wrapper,我们主要关心最核心的两个概念,wrappedValueprojectedValue是什么就行了:

@State

这是第二次提到了,在Property Observers一节里预告过,基本上点@的,大都为Property Wrapper的内容。

@State private var foo: Int
init() {
    _foo = .init(initiaValue: 5)
}

注意_$的区别。

@StateObject & @ObservedObject

@StateObject V.S. @State

@StateObject V.S. @ObservedObject

@main
struct EmojiArtApp: App {
    // stateObject, source of truth
    // defined in the app
    @StateObject var paletteStore = PaletteStore(named: "default")

    var body: some Scene {
    DocumentGroup(newDocument: { EmojiArtDocument() }) { config in
        EmojiArtDocumentView(document: config.document)
            .environmentObject(paletteStore)  // passed by environment
        }
    }
}

@Binding

struct MyView: View {
      @State var myString = “Hello”               // 1
      var body: View {
          OtherView(sharedText: $myString)        // 2
      }
  }
  struct OtherView: View {
      @Binding var sharedText: string             // 3
      var body: View {
          Text(sharedText)                        // 4
          TextField("shared", text: $sharedText)  // 5 _myString.projectValue.projectValue
      }
}
  1. _myString是实际变量,包含一个wrappedValue,一个projectedValue
  2. myString就是_myString.wrappedValue
  3. $myString_myString.projectedValue
    • 是一个Binding<String>,传值和接值用的就是它
    • 所以传$myString的地方也可以用_myString.projectedValue代替,学习阶段的话
  4. 要把projectedValue层层传递下去,并不是用同一个projectedValue,而是设计成了Binding<T>
    • 参考上面代码块的第5条

其它

比如你的view是一个小组件,里面有一个Binding var user: User,那么在preview里面怎么传入这个User呢?用常量:

static var preview: some View {
    myView(user: .constant(User(...)))
}

@EnvironmenetObject

@ObservedObject用法稍有点不同,有单独的赋值接口:

let myView = MyView().environmentObject(theViewModel)
// 而@ObservedObject是一个普通的属性
let myView = MyView(viewModel: theViewModel)

// Inside the View ...
@EnvironmentObject var viewModel: ViewModelClass 
// ... vs ...
@ObservedObject var viewModel: ViewModelClass

@Environment

view.environment(\.colorScheme, .dark)

so:

// someView pop 一个 modal 的 myView,传递 environment
someView.sheet(isPresented: myCondition){
    myView(...init...)
    .enviroment(\.colorScheme, colorScheme) 
}

除了深色模式,还有一个典型的应用场景就是编辑模式\.editMode,比如点了编辑按钮后。

EditButton是一个封装了UI和行为的控件,它只做一件事,就是更改\.editmode这个环境变量(的isEditing)

@Publisher

It is an object that emits values and possibly a failure object if it fails while doing so.

Publisher<Output, Failure>

订阅

一种简单用法,sink:

cancellable = myPublisher.sink(
    receiveCompletion:{resultin...}, //result is a Completion<Failure> enum
        receiveValue: { thingThePublisherPublishes in . . . }
  )

返回一个Cancellable,可以随时.cancel(),只要你持有这个cancellable,就能随时用这个sink

View有自己的订阅方式:

.onReceive(publisher) { thingThePublisherPublishes in
    // do whatever you want with thingThePublisherPublishes 
}
  1. .onReceive will automatically invalidate your View (causing a redraw).
  2. 既然参数是publisher,所以是一个binding的变量,即带$使用:
.onReceive($aBindData) { bind_data in 
    // my code
}

publisher来源:

  1. $ in front of vars marked @Published
    • 还记得$就是取的projectedValue吗?
    • 一般的projectedValue是一个Binding,Published的是是个Publisher
  2. URLSession’s dataTaskPublisher (publishes the Data obtained from a URL)
  3. Timer’s publish(every:) (periodically publishes the current date and time as a Date)
  4. NotificationCenter’s publisher(for:) (publishes notifications when system events happen)

如果你有一个ObservedObject(Document),它里面有一个@Publisher(background),那么注意以下两者的区别:

.onReceive只能接收Publisher的推送,而事实上,onChange(一般用于接收ObservedObject或State)同样也能接收Publisher。

上一篇 下一篇

猜你喜欢

热点阅读