我的应用程序允许用户销售运动鞋等产品。出现在用户供稿中的运动鞋基于发布了用户附近物品的卖家。我使用GeoFire来获取卖方的位置,并且一切正常。如果用户在附近没有添加任何新数据/运动鞋时使用pullToRefresh,则无需刷新列表。
让我感到困扰的地方是用户pullToRefresh时,如何确定附近的一个全新卖家或添加了更多运动鞋的同一卖家添加了新商品?
例如userA的邮政编码为10463,在20英里半径范围内有2个卖方。那些卖家要出售的任何运动鞋都将出现在用户的供稿中。但是,第3个卖家可以过来发布一双运动鞋,或者前2个卖家中的任何一个都可以添加另外一双。如果用户pullsToRefesh,则会显示这些项目,但是如果不添加任何内容,则pullToRefresh不应执行任何操作。
如果不需要,我不想不必要地重新运行Firebase代码。唯一的方法是先检查帖子,然后参考以查看2位卖家或附近的一位全新卖家是否添加了新的运动鞋。
代码:
let refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
return refreshControl
}()
@objc func pullToRefresh() {
// if there aren't any new nearby sellers or current sellers with new items then the two lines below shouldn't run
arrOfPosts.removeAll() // this is the array that has the collectionView's data. It gets populated in thirdFetchPosts()
firstGetSellersInRadius(miles: 20.0)
}
override func viewDidLoad() {
super.viewDidLoad()
firstGetSellersInRadius(miles: 20.0) // the user can change the mileage but it's hardcoded for this example
}
// 1. I get the user's location and then get all the nearby sellers
func firstGetSellersInRadius(miles: Double) {
// user's location
guard let currentLocation = locationManager.location else { return }
let lat = currentLocation.coordinate.latitude
let lon = currentLocation.coordinate.longitude
let location = CLLocation(latitude: lat, longitude: lon)
let radiusInMeters = (miles * 2) * 1609.344 // 1 mile == 1609.344 meters
let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: radiusInMeters, longitudinalMeters: radiusInMeters)
let geoFireRef = Database.database().reference().child("geoFire")
regionQuery = geoFireRef?.query(with: region)
queryHandle = regionQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
let geoModel = GeoModel()
geoModel.userId = key
geoModel.location = location
self.arrOfNearbySellers.append(geoModel)
})
regionQuery?.observeReady({
self.secondLoopNearbySellersAndGetTheirAddress(self.arrOfNearbySellers)
})
}
// 2. I have to grab the seller's username and profilePic before I show their posts because they're shown along with the post
func secondLoopNearbySellersAndGetTheirAddress(_ geoModels: [GeoModel]) {
let dispatchGroup = DispatchGroup()
for geoModel in geoModels {
dispatchGroup.enter()
if let userId = geoModel.userId {
let uidRef = Database.database().reference().child("users")?.child(userId)
uidRef.observeSingleEvent(of: .value, with: { [weak self](snapshot) in
guard let dict = snapshot.value as? [String: Any] else { dispatchGroup.leave(); return }
let profilePicUrl = dict["profilePicUrl"] as? String
let username = dict["username"] as? String
let userModel = UserModel()
userModel.profilePicUrl = profilePicUrl
userModel.username = username
self?.arrOfSellers.append(userModel)
dispatchGroup.leave()
})
}
}
dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
self?.thirdFetchPosts(self!.arrOfSellers)
}
}
// 3. now that I have their address I fetch their posts
func thirdFetchPosts(_ userModels: [UserModel]) {
let dispatchGroup = DispatchGroup()
var postCount = 0
var loopCount = 0
for userModel in userModels {
dispatchGroup.enter()
if let userId = userModel.userId {
let postsRef = Database.database().reference().child("posts")?.child(userId)
postsRef?.observe( .value, with: { [weak self](snapshot) in
postCount = Int(snapshot.childrenCount)
guard let dictionaries = snapshot.value as? [String: Any] else { dispatchGroup.leave(); return }
dictionaries.forEach({ [weak self] (key, value) in
print(key, value)
loopCount += 1
guard let dict = value as? [String: Any] else { return }
let postModel = PostModel(userModel: userModel, dict: dict)
self?.arrOfPosts.append(postModel)
if postCount == loopCount {
dispatchGroup.leave()
postCount = 0
loopCount = 0
}
})
})
}
}
dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
self?.fourthRemoveQueryObserverReloadCollectionView()
}
}
// 4. now that I have all the posts inside the arrOfPosts I can show them in the collectionView
func foutrhRemoveQueryObserverReloadCollectionView() {
DispatchQueue.main.async { [weak self] in
self?.arrOfPosts.sort { $0.postDate ?? 0 > $1.postDate ?? 0}
self?.refreshControl.endRefreshing()
if let queryHandle = self?.queryHandle {
self.regionQuery?.removeObserver(withFirebaseHandle: queryHandle)
}
self?.collectionView.reloadData()
self?.arrOfNearbySellers.removeAll()
self?.arrOfSellers.removeAll()
}
}