问题描述
我希望能够将对@Published属性的引用作为参数传递给其他对象,以便其他对象可以使用,编辑和查看该属性上的数据,并且我希望在保留Property功能的同时做到这一点Swift中的包装器
这是我的例子。我创建一个MainStore对象。它具有@Published名称数组。我可以在整个应用程序中使用该对象,也可以在names
中更改数据,任何订阅的地方都会得到更新。
class MainStore {
@Published var names: [String]
init(names: [String]) {
self.names = names
}
}
现在我要创建第二个商店。它具有一些附加功能,需要更加集中,但是我希望它引用MainStore中的names
属性。当MainStore.names被更新时,我也希望SecondStore.names也被更新。当SecondStore.names更新时,我也希望MainStore.names也更新。
class SecondStore {
@Published var names: [String]
init(@Published names: [String]) {
self.names = names
}
}
我也希望使用@Published属性包装的语法
例如SecondStore.names.append("Billy")
和SecondStore.$names.sink() { }
有没有办法做到这一点,如果不是,建议的做法是完成我的一般指导?
解决方法
您可以将import Data.Either (either)
import Text.Printf (printf)
data Record = Record
{ fieldA :: String,fieldB :: String,fieldC :: String
} deriving (Show,Eq)
type Err = String
setField :: String -> String -> Either Err String
setField field value
| length value > 0 = Right value
| otherwise = Left $ printf "value for field %s is to short" field
setFieldA :: String -> Either Err String
setFieldA = setField "fieldA"
setFieldB :: String -> Either Err String
setFieldB = setField "fieldB"
setFieldC :: String -> Either Err String
setFieldC = setField "fieldC"
makeRecord :: Either Err Record
makeRecord = Record
<$> setField "fieldA" "valueA"
<*> setField "fieldB" "valueB"
<*> setField "fieldC" "valueC"
makeRecord' :: Either Err Record
makeRecord' = Record
<$> setFieldA "valueA"
<*> setFieldB "valueB"
<*> setFieldC "valueC"
recordFromEither :: Either Err Record -> Maybe Record
recordFromEither r =
case r of
Right v -> Just $ v
Left _ -> Nothing
main :: IO ()
main = putStrLn $ output
where
output = case makeRecord of
Right v -> show v
Left err -> show err
main' :: IO ()
main' = putStrLn $ either id show makeRecord'
对象传递到MainStore
,然后收听到对SecondStore
属性所做的更改。
mainStore.names
class MainStore {
@Published var names: [String]
init(names: [String]) {
self.names = names
}
}
请注意,在class SecondStore {
@Published var names: [String] = []
private var cancellables = Set<AnyCancellable>()
init(mainStore: MainStore) {
// listen to the `$names` publisher
mainStore.$names
// all `@Published` properties must be updated on the `main` thread
.receive(on: RunLoop.main)
// assign received value to self.names
.sink { [weak self] in
self?.names = $0
}
// keep it in memory so it won't be cancelled
.store(in: &cancellables)
}
}
部分中,可能存在较强的参考周期。
这就是为什么使用.sink
的原因。您可以在此处了解更多信息:Weak Self in Swift Made Easy: What it is and why it’s needed