swift keypath
KeyPath refers to a property itself instead of property’s value. They‘re useful when you want to perform operations on property, rather on the value behind it.
KeyPath是指属性本身而不是属性的值。 当您要对属性(而不是属性值)执行操作时,它们很有用。
Let’s take an example:
让我们举个例子:
KeyPath let us refer to the properties without accessing them using .
like this: \type name.path
.
KeyPath让我们无需使用访问属性即可引用属性.
像这样: \type name.path
。
nameKeyPath
syntax in the screenshot is <User, String> where User
is type name and String
is path name.
屏幕快照中的nameKeyPath
语法为<User,String>,其中User
为类型名称, String
为路径名称。
This struct has an issue now, it won’t let me update nameKeyPath
value as it’s declared let
. It gives below error on assigning value so to update nameKeyPath
value from outside of type need to declare it public.
这个结构现在有问题,因为声明为let
,所以不会让我更新nameKeyPath
值。 它在分配值时出现以下错误,因此从类型外部更新nameKeyPath
值需要将其声明为public。
Let’s make the name
of User
public, on making it public key path becomes WritableKeyPath<User, String>
. Values can be assigned only on WritableKeyPath
让我们将User
的name
User
public,将其公钥路径变为WritableKeyPath<User, String>
。 只能在WritableKeyPath
上分配值
Although it helps in meeting criteria but the type is mutated from outside, had to compromise by making name
and user
property var
.
尽管它有助于满足条件,但是类型是从外部变异的,但必须通过使name
和user
属性var
折衷。
Let’s use private(set)
让我们使用private(set)
Now I have 2 problems:
现在我有两个问题:
I don’t have access to
WritableKeyPath
outside Type, so compiler gives error on assigning data using KeyPath我无法访问Type之外的
WritableKeyPath
,因此编译器在使用KeyPath分配数据时出现错误- Another is I are mutating property, ‘mutating’ function can only be called on vars 另一个是我正在变异属性,“变异”功能只能在vars上调用
To mitigate this problem, I created a protocol that can be called on any struct to make a new copy with only one property changed.
为了缓解这个问题,我创建了一个协议,可以在任何结构上调用该协议以仅更改一个属性即可创建新副本。
使用KeyPath修改Struct属性值 (Modify Struct Property value using KeyPath)
Using update
function I can update value of any property.
使用update
功能,我可以更新任何属性的值。
First KeyPath
is casted toWritableKeyPath
and then update(keyPath:value:)
is called on it.
首先将KeyPath
update(keyPath:value:)
为WritableKeyPath
,然后在其上调用update(keyPath:value:)
。
This solution works perfectly for updating any property value but let’s say I have to update the value of 3 properties that requires us to repeat the code of casting multiple times. So let’s move casting to protocol extension. While moving casting code I realized that instead of KeyPath
I should pass PartialKeyPath
which just accepts root type.
该解决方案非常适合更新任何属性值,但是假设我必须更新3个属性的值,这需要我们重复多次铸造代码。 因此,让我们将强制转换扩展到协议扩展。 在移动转换代码时,我意识到我应该传递PartialKeyPath
而不是KeyPath
,该PartialKeyPath
仅接受根类型。
PartialKeyPath — It’s useful when you need to send keyPath to another function or you want to store keypaths of similar type.
PartialKeyPath-当您需要将keyPath发送到另一个函数或要存储类似类型的键路径时,此功能很有用。
AnyKeyPath — It’s useful when you want to store key paths of any type into an array.
AnyKeyPath —在要将任何类型的键路径存储到数组中时很有用。
Finally 🎉 KeyPathEditable protocol can be conformed by any struct to make a new copy with only one property changed
最后🎉KeyPathEditable方案可以通过任何结构效法作出新的副本只有一个属性改变
Complete source code can be found here
完整的源代码可以在这里找到
使用KeyPath修改类属性 (Modify class property using KeyPath)
We can’t use existing KeyPathEditable
protocol here as that creates a copy on modifying property value. Let’s create a new protocol to modify a property value only
我们不能在这里使用现有的KeyPathEditable
协议,因为它会在修改属性值时创建一个副本。 让我们创建一个新协议以仅修改属性值
If you notice apart from copy
there is one more difference b/w this protocol and previous protocol. With class
type we can’t specify Self
type in protocol, it gives error:
如果您发现除copy
外,本协议与以前的协议还有另一个不同之处。 对于class
类型,我们无法在协议中指定“ Self
类型,但会出现错误:
Error: protocol can only be used as a generic constraint because it has Self or associated type requirements
错误:协议只能用作通用约束,因为它具有“自我”或相关联的类型要求
To fix this error I used associatedtype Root
and passed type in function argument
要解决此错误,我使用了associatedtype Root
并在函数参数中传递了类型
Protocol can bee consumed like this:
协议可以像这样消耗蜂:
Finally 🎉 ReferenceKeyPathEditable protocol can be conformed by any class to modify property value while keeping property setter private for other types.
最后,任何类都可以使用ReferenceKeyPathEditable协议来修改属性值,同时使属性设置器对其他类型保持私有。
Complete source code can be found here
完整的源代码可以在这里找到
具有功能的KeyPath: (KeyPath with Functions:)
map()
地图()
KeyPath with functions can be used when you have a requirement to work with a single property. I mostly like this for high level functions.
当您需要使用单个属性时,可以使用带有函数的KeyPath。 我最喜欢这种高级功能。
It helps while reading as well. In a map with closure, our intention is to map user by name property but we specify by value. Although it works but keyPath fits better here as by keyPath we say to map by given path.
它也有助于阅读。 在带闭包的地图中,我们的意图是通过name属性映射用户,但我们通过值进行指定。 尽管它可以工作,但是keyPath在这里更适合,因为我们说要通过给定路径映射keyPath。
filter() — keypath can be used with a filter as well
filter() -键路径也可以与过滤器一起使用
sort()
分类()
Swift standard library doesn’t provide a function to sort by keypath but we can add utility function in extension:
Swift标准库没有提供按键路径排序的函数,但是我们可以在扩展中添加实用程序函数:
Complete source code can be find here
完整的源代码可以在这里找到
P.S: It was fun playing with it
PS:玩起来很有趣
For more insights, this article is worth to read
有关更多见解,本文值得一读
您可以通过以下方式与我联系: (You can reach out to me at:)
Linkedin: Aaina Jain
Linkedin: Aaina Jain
Twitter: __aainajain
推特: __aainajain
翻译自: https://medium.com/flawless-app-stories/the-story-of-my-experiments-with-swift-keypath-3a55809ffecf
swift keypath