实时组合@published 数组的最佳实践?
Best practices for combining @published arrays in real time?
所以我正在编写代码,可以使用本地(MultiPeers 和低功耗蓝牙)和网络(使用实时数据库按位置查找附近用户)找到附近的用户
class ViewModel: ObservableObject{
@Published nearbyMultipeers: [User] = []
@Published nearbyBluetoothUsers: [User] = []
@Published nearbyGeoUsers: [User] = []
// This gets the nearby users by GeoLocation and updates the nearbyGeoUsers array
func getNearbyUsersByGeoLocation(){ /* ... */ }
// This will loop through all of the nearby users obtained via multipeer and grab their user data from the database and append it to the nearbyMultipeers array
func getUsersFromPeers(nearbyPeers: [Peer])( /* ... */ )
}
现在这些列表将不断更新(因为 multipeers 仅在应用程序处于前台时有效,您自然会进出附近用户的范围)。
有时会出现重复数据的问题,nearbyBluetoothUsers
可能包含一些nearbyMultipeers
,nearbyGeoUsers
可能包含一些nearbyBluetoothUsers
等,我需要一个方法实时显示所有这些用户的列表而不显示重复数据。
为简单起见,假设我将它们显示在这样的列表中
struct NearbyUsersView: View {
// This observable object contains information on the nearby peers //(multipeers)
// This is how I get the nearby peers
@ObservableObject var multipeerDataSource: MultipeerDataSource
var body: some View {
VStack{
// Ideally I would display them in a scrollable list of some sort, this is
// just to illustrate my issue
ForEach(viewModel.$allUsersExcludingDuplicates){. user in
Text(user.name)
}
}
.onAppear{
viewModel.getNearbyUsersByGeoLocation()
}
.onChange(of: multipeerDataSource.$nearbyPeers) { nearbyPeers
// this array contains the nearby peers (users)
// We have to actually convert it to a `User`, or fetch the user data because //the objects here won't be the actual data it may just contain the user Id or some sort // so we have to grab the actual data
viewModel.getUsersFromPeers(nearbyPeers)
}
}
}
我省略了通过蓝牙抓取,因为没有必要理解这个问题。
现在我唯一能想到的NearbyUsersView
就是做
ForEach((viewModel.nearByMultipeers + viewModel.nearbyBluetoothUsers + viewModel.nearbyGeoUsers).removeDuplicates()) { user in /* ... */ }
但有些事情告诉我,我不会有预期的结果
您可以简单地在 ViewModel
中使用计算变量,假设 User
符合 Equatable
,如下所示:
public var nearbyUsers: Set<User> {
Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers)))
}
这会将您的数组转换为集合,并通过多个并集创建一个集合。集合不能有重复项。如果你需要它作为一个数组,你可以这样做:
public var nearbyUsers: [User] {
Array(Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers))))
}
最后,如果 User
符合 Comparable
,您可以 return 像这样的排序数组:
public var nearbyUsers: [User] {
Array(Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers)))).sorted()
}
所以我正在编写代码,可以使用本地(MultiPeers 和低功耗蓝牙)和网络(使用实时数据库按位置查找附近用户)找到附近的用户
class ViewModel: ObservableObject{
@Published nearbyMultipeers: [User] = []
@Published nearbyBluetoothUsers: [User] = []
@Published nearbyGeoUsers: [User] = []
// This gets the nearby users by GeoLocation and updates the nearbyGeoUsers array
func getNearbyUsersByGeoLocation(){ /* ... */ }
// This will loop through all of the nearby users obtained via multipeer and grab their user data from the database and append it to the nearbyMultipeers array
func getUsersFromPeers(nearbyPeers: [Peer])( /* ... */ )
}
现在这些列表将不断更新(因为 multipeers 仅在应用程序处于前台时有效,您自然会进出附近用户的范围)。
有时会出现重复数据的问题,nearbyBluetoothUsers
可能包含一些nearbyMultipeers
,nearbyGeoUsers
可能包含一些nearbyBluetoothUsers
等,我需要一个方法实时显示所有这些用户的列表而不显示重复数据。
为简单起见,假设我将它们显示在这样的列表中
struct NearbyUsersView: View {
// This observable object contains information on the nearby peers //(multipeers)
// This is how I get the nearby peers
@ObservableObject var multipeerDataSource: MultipeerDataSource
var body: some View {
VStack{
// Ideally I would display them in a scrollable list of some sort, this is
// just to illustrate my issue
ForEach(viewModel.$allUsersExcludingDuplicates){. user in
Text(user.name)
}
}
.onAppear{
viewModel.getNearbyUsersByGeoLocation()
}
.onChange(of: multipeerDataSource.$nearbyPeers) { nearbyPeers
// this array contains the nearby peers (users)
// We have to actually convert it to a `User`, or fetch the user data because //the objects here won't be the actual data it may just contain the user Id or some sort // so we have to grab the actual data
viewModel.getUsersFromPeers(nearbyPeers)
}
}
}
我省略了通过蓝牙抓取,因为没有必要理解这个问题。
现在我唯一能想到的NearbyUsersView
就是做
ForEach((viewModel.nearByMultipeers + viewModel.nearbyBluetoothUsers + viewModel.nearbyGeoUsers).removeDuplicates()) { user in /* ... */ }
但有些事情告诉我,我不会有预期的结果
您可以简单地在 ViewModel
中使用计算变量,假设 User
符合 Equatable
,如下所示:
public var nearbyUsers: Set<User> {
Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers)))
}
这会将您的数组转换为集合,并通过多个并集创建一个集合。集合不能有重复项。如果你需要它作为一个数组,你可以这样做:
public var nearbyUsers: [User] {
Array(Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers))))
}
最后,如果 User
符合 Comparable
,您可以 return 像这样的排序数组:
public var nearbyUsers: [User] {
Array(Set(nearbyMultipeers).union(Set(nearbyBluetoothUsers).union(Set(nearbyGeoUsers)))).sorted()
}