只读属性_rxswift只读属性和读写属性包装器

只读属性

Note: I know, that in light of Apple’s Combine framework, continue to develop on RxSwift may seem a “mauvais ton”, but far not every new project may start with iOS 13 minimal support, and I believe this will be the case at least for an year. Moreover, there are tons of existing projects which must support earlier iOS versions and still demand on reactive programming frameworks.

注意:我知道,鉴于苹果公司的Combine框架,继续在RxSwift上进行开发似乎是“大麻烦”,但是到目前为止,并非每个新项目都可能从iOS 13的最小支持开始,而且我相信至少如此一年了 而且,有许多现有项目必须支持早期的iOS版本,并且仍然需要响应式编程框架。

BehaviorRelay和RxProperty (BehaviorRelay and RxProperty)

Any Swift developer who worked with RxSwift knows that Observables and Subjects lack the ability to store the last value. Before RxSwift 5.0.0 there was the Variable generic class for this purpose, now it has been substituted with the BehaviorRelay which technically is not even part of RxSwift, but RxRelay module.

任何使用RxSwift的Swift开发人员都知道ObservablesSubjects缺乏存储最后一个值的能力。 在RxSwift 5.0.0之前,存在用于此目的的Variable泛型类,现在已将它替换为BehaviorRelay ,从技术上讲,它甚至不是RxSwift的一部分,而是RxRelay模块。

A developer who just starting to use RxSwift may be confused, what’s the difference between PublishSubject, BehaviorSubject, PublishRelay, and BehaviorRelay.

刚开始使用RxSwift的开发人员可能会感到困惑, PublishSubjectBehaviorSubjectPublishRelayBehaviorRelay之间有什么区别。

  • Publish vs Behavior. The first doesn’t store the last value, while the last - does.

    发布行为。 第一个不存储最后一个值,而最后一个则存储。

  • Subject vs Relay. The last doesn’t through an error and can’t be terminated, while the first - can.

    主题 vs 接力 。 最后一个不会出错,也不能终止,而第一个可以。

As you may already know, RxSwift is used to glue components in the app: a ViewModel with a ViewController in MVVM, an Interactor with Services in RIBs, a Middleware with a Store in Redux.

您可能已经知道,RxSwift用于粘合应用程序中的组件:MVVM中具有ViewController的ViewModel,RIB中具有服务的Interactor,Redux中具有商店的中间件。

Normally, a PublishSubject is used to propagate an event, while BehaviorRelay to share some value or a state. The common interface for a ViewModel looks like:

通常, PublishSubject用于传播事件,而BehaviorRelay用于共享某些值或状态。 ViewModel的通用接口如下所示:

Image for post
Source 资源

There is a slight problem with this ViewModel declaration though: its state is modifiable outside. Because even it is only a get property, .accept() method, which modifies the value, is available. This totally breaks one of the fundamental rules of OOP - encapsulation.

但是,此ViewModel声明存在一个小问题:其状态可以在外部修改。 因为即使它只是一个get属性,所以。 可以修改值的accept()方法。 这完全打破了OOP的基本规则之一-封装。

Someone may propose to use Observable in the protocol instead of BehaviorRelay, i.e. something like that:

有人可能会建议在协议中使用Observable而不是BehaviorRelay ,即类似这样的东西:

Image for post
Source 资源

However, Observable does not retain the last value, so one can’t just read it at any time. In some cases, this is not convenient and may require more logic and code to workaround.

但是, Observable不会保留最后一个值,因此不能随时读取它。 在某些情况下,这不方便,并且可能需要更多的逻辑和代码来解决。

This is a well-known problem, and there is an easy solution for it - RxProperty. It is basically a wrapper around BehaviorRelay which provides only read interface, no write one. It is kind of read-only BehaviorRelay. There was plenty of discussions here and there, about adding this class to the main RxSwift module, but this did not make to happen.

这是一个众所周知的问题,并且有一个简单的解决方案-RxProperty 。 它基本上是BehaviorRelay的包装,它仅提供读接口,不提供写接口。 这是一种只读的BehaviorRelay。 关于将该类添加到主要的RxSwift模块中, 这里 到处都有很多讨论,但这没有实现。

With this wrapper encapsulation problem get solved:

使用此包装器封装问题得到解决:

Image for post
Source 资源

However, it is a bit ugly and inconvenient to declare a private BehaviorRelay property as a complementary accessory for each RxProperty you have in the interface. And here is where Swift property wrappers come to rescue.

但是,将私有BehaviorRelay属性声明为接口中具有的每个RxProperty的补充附件,这有点丑陋且不便。 这就是Swift属性包装器来救援的地方。

物业包装 (Property wrappers)

This Swift feature was introduced in 5.1 version and as stayed in the doc:

这个Swift功能是在5.1版本中引入的,并保留在doc中

A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property.

属性包装器在管理属性存储方式的代码与定义属性的代码之间增加了一层隔离。

In practice, the sense of wrappers behind this not very clear sentence is to write some property-related functionality once and use it for each property where it is applicable. As a very basic example: @UserDefault property wrapper, which adds read-write functionality to UserDefaults for a property value using some key.

实际上,这个不太清晰的句子后面的包装器的含义是只编写一些与属性相关的功能,并将其用于适用的每个属性。 作为一个非常基本的示例: @UserDefault属性包装器,它使用某些键为属性值添加了对UserDefaults的读写功能。

I’ll not go into details of property wrappers syntax and functionality, there are a lot of blog posts on this topic in Web, in particular #1, #2.

我不会详细介绍属性包装器的语法和功能,Web上有很多关于此主题的博客文章,尤其是#1#2

RxProperty的@ReadWrite属性包装器 (@ReadWrite property wrapper for RxProperty)

Now we come to the main topic of this story. Here is the property wrapper which adds write functionality to the read-only RxProperty:

现在我们来谈谈这个故事的主题。 这是属性包装器,它将包装功能添加到只读RxProperty:

Image for post
Source 资源

It adds .accept() method and access to the internal BehaviorRelay of the wrapped RxProperty. It all makes sense if this property wrapper is declared in the same file as RxProperty class, and _behaviorRelay has fileprivate access level.

它添加.accept()方法并访问包装的RxProperty的内部BehaviorRelay 。 如果在与RxProperty类相同的文件中声明此属性包装器,并且_behaviorRelay具有fileprivate访问级别,则这一切都有意义。

With this small addition our ViewModel declaration could be like:

有了这小小的添加,我们的ViewModel声明可能像:

Image for post
Source 资源
  • Encapsulation principle persisted, because plain RxProperty provides only read-only access.

    封装原理得以保留 ,因为普通RxProperty仅提供只读访问。

  • No need for a complimentary BehaviorRelay declaration makes this code just perfect 👌.

    无需额外的BehaviorRelay声明,此代码就非常完美。

NOTE: Thanks to Alexey Naumov, using a Swift property wrapper projectedValue feature, it is possible to solve this task even in more elegant way:

注意:感谢Alexey Naumov ,使用Swift属性包装器projectedValue 功能,甚至可以以更优雅的方式解决此任务:

Image for post
Source 资源

In this version, internal BehaviorRelay may be accessed using $ notation, like: $state.accept(newValue)

在此版本中,可以使用$表示法访问内部BehaviorRelay ,例如: $ state.accept(newValue)

The updated RxProperty solution may be found in my fork. Feel free to ⭐️ it if you like. Thank you for attention!

更新的RxProperty解决方案可以在我的fork中找到。 如果您愿意,可以随时⭐️。 感谢您的关注!

翻译自: https://medium.com/flawless-app-stories/rxswift-read-only-property-and-read-write-property-wrapper-608f3014359f

只读属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值