- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我像在 Firebase 事件数据库中一样实现了该系统。点赞计数器位于 EventModel -> likesInfo -> likesNumber
处。问题在于数据发散,例如,如果两个用户快速(0.5秒)喜欢/不喜欢(反之亦然),那么可能在测试完成后,两个用户都停止在不喜欢上,likesNumber将为1 (错误)有时差异可能是 4-6 个值。一开始我是用runTransactionBlock
实现到应用程序中的,后来我想通过事件中感兴趣的用户数量来统计,并使用云函数来实现这一点,但结果更糟糕比应用程序中的内容要多。我见过一些示例,包括 firebase 示例(其中 one),但其中一些示例不适合,因为如果事件有很多数据,则有必要在事件模型中存储大量数据。喜欢。其他的我也用过,但没有什么效果。我附上下面的代码。请告诉我如何最好地实现这个系统?
来自应用程序的代码
private func likeNumber(_ eventID: String, isLike: Bool, success: ((_ isCommited: Bool) -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
let eventRef = Database.database().reference().child(self.MainPath.events.rawValue).child(eventID).child(self.SubPath.likesInfo.rawValue).child(self.SubPath.likesNumber.rawValue)
eventRef.runTransactionBlock({ (currentData) -> TransactionResult in
var likesNumber = currentData.value as? Int ?? 0
debugPrint("likesNumber", likesNumber)
if isLike {
likesNumber += 1
} else {
likesNumber -= 1
}
if likesNumber < 0 {
likesNumber = 0
}
debugPrint("sumarry likesNumber", likesNumber)
currentData.value = likesNumber
return TransactionResult.success(withValue: currentData)
}, andCompletionBlock: { (error, commited, snap) in
if let _error = error {
debugPrint("_error", _error.localizedDescription)
fail?(_error)
return
}
if commited {
debugPrint("commited", commited)
}
success?(commited)
debugPrint("snap", snap?.value ?? "")
})
}
}
云功能
var functions = require('firebase-functions');
var eventManager = require('../Managers/event-manager');
module.exports = functions.database.ref('eventLikedUsers/{eventID}/{userID}').onDelete(event => {
const eventID = event.params.eventID;
return eventManager.incrementLikesNumber(eventID, false);
});
module.exports = functions.database.ref('eventLikedUsers/{eventID}/{userID}').onCreate(event => {
const eventID = event.params.eventID;
return eventManager.incrementLikesNumber(eventID, true);
});
来自EventManager
的代码
exports.incrementLikesNumber = function incrementLikesNumber(eventID, isLike) {
return new Promise((resolve, reject) => {
const eventRef = admin.database().ref()
.child('events')
.child(eventID)
.child('likesInfo')
.child('likesNumber');
const prom = eventRef.transaction(currentData => {
if (isLike) {
return (currentData || 0) + 1;
} else {
return (currentData || 1) - 1;
}
});
return prom
.then(() => {
return resolve('success operation')
}).catch(error => {
return reject(error)
})
});
};
最佳答案
我在 EventsLikeManager
中为一个事件的喜欢/不喜欢函数创建了一个队列。例如,如果为事件 id 1 执行某个功能,并且请求为事件 id 1 执行相同的功能,则第二个请求将排队并等待第一个请求被执行。代码没有重构,完全可以工作,通过了测试。
class EventsLikeManager {
// MARK: - Init
private init() { }
static let shared = EventsLikeManager()
private let MainPath = EventsPaths.MainPath.self
private let SubPath = EventsPaths.SubPath.self
private let systemQueue = DispatchQueue(label: "com.myapp.EventsLikeManager.systemQueue")
// id, time,
private var dict = [String : [EventSystemLikeDislikeModel]]()
// MARK: - Like actions
func likeEvents(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
guard newSystemEvent(event) else { return }
_likeEvents(event, success: success, fail: fail)
}
private func _likeEvents(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
FirebasePerformanceManager.shared.likeDislikeAction(true)
DispatchQueue.global(qos: .background).async {
if event.systemInfo.sourceIndex == EventSystemModel.Source.firebase.index {
self.eventLikeInternalSourceAction(event, success: success, fail: fail)
} else {
self.eventLikeOutsourceAction(event, success: success, fail: fail)
}
}
}
private func eventLikeOutsourceAction(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
Auth.auth().currentUser?.getIDTokenForcingRefresh(true, completion: { (token, error) in
guard token != nil else { return }
let timestamp = Date().currentTimestamp
event.systemTimeProperties.creationTimestamp = timestamp
event.systemTimeProperties.updateTimestamp = timestamp
event.systemInfo.sourceIndex = EventSystemModel.Source.firebase.index
self.createEvent(event, success: {
self.userLikedEvent(event.id, notExists: { self.likeAction(event, timestamp: timestamp, success: success, fail: fail)
}, success: { (likeModel) in
// dislike
self.dislikeAction(event, success: success, fail: fail)
}, fail: fail)
}, fail: { (error) in
})
})
}
}
private func eventLikeInternalSourceAction(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
userLikedEvent(event.id, notExists: {
self.likeAction(event, success: success, fail: fail)
}, success: { (likeModel) in
// dislike
self.dislikeAction(event, success: success, fail: fail)
}, fail: fail)
}
func createEvent(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
let dispatchGroup = DispatchGroup()
var commonError: Error?
let eventRef = Database.database().reference().child(self.MainPath.events.rawValue).child(event.id)
dispatchGroup.enter()
eventRef.runTransactionBlock({ (currentData) -> TransactionResult in
if (currentData.value as? [String : Any]) != nil {
debugPrint("TransactionResult.abort()")
return TransactionResult.abort()
} else {
dispatchGroup.enter()
self.createEventLocation(event, success: {
dispatchGroup.leave()
}, fail: { (error) in
dispatchGroup.leave()
})
currentData.value = event.toJSON()
return TransactionResult.success(withValue: currentData)
}
}, andCompletionBlock: { (error, isCommited, snap) in
commonError = error
debugPrint("isCommited", isCommited)
dispatchGroup.leave()
})
dispatchGroup.notify(queue: .global(qos: .background), execute: {
if let error = commonError {
fail?(error)
} else {
success?()
}
})
}
}
private func createEventLocation(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
let eventLocationRef = Database.database().reference().child(self.MainPath.eventsLocations.rawValue)
guard let geofire = GeoFire(firebaseRef: eventLocationRef) else { return }
let coordinate = event.location.coordinate
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
geofire.setLocation(location, forKey: event.id, withCompletionBlock: { (error) in
if let _error = error {
fail?(_error)
} else {
success?()
}
})
}
}
}
// MARK: - Likes' functions
extension EventsLikeManager {
private func likeAction(_ event: EventModel, timestamp: Double? = nil, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
var finalTimestamp = Date().currentTimestamp
if let _timestamp = timestamp {
finalTimestamp = _timestamp
}
var commonError: Error?
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
self.likeNumber(event.id, isLike: true, success: { (isCommited) in
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.enter()
self.addEventToUserList(event, timestamp: finalTimestamp, success: {
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.enter()
self.addUserToEventUsersList(event.id, timestamp: finalTimestamp, success: {
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.notify(queue: .main, execute: {
self.checkSystemEventQueue(event)
if let error = commonError {
fail?(error)
} else {
success?()
}
FirebasePerformanceManager.shared.likeDislikeAction(false)
})
}
}
private func likeNumber(_ eventID: String, isLike: Bool, success: ((_ isCommited: Bool) -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
let eventRef = Database.database().reference().child(self.MainPath.events.rawValue).child(eventID).child(self.SubPath.likesInfo.rawValue).child(self.SubPath.likesNumber.rawValue)
eventRef.runTransactionBlock({ (currentData) -> TransactionResult in
var likesNumber = currentData.value as? Int ?? 0
debugPrint("likesNumber", likesNumber)
if isLike {
likesNumber += 1
} else {
likesNumber -= 1
}
if likesNumber < 0 {
likesNumber = 0
}
debugPrint("sumarry likesNumber", likesNumber)
currentData.value = likesNumber
return TransactionResult.success(withValue: currentData)
}, andCompletionBlock: { (error, commited, snap) in
if let _error = error {
debugPrint("_error", _error.localizedDescription)
fail?(_error)
return
}
if commited {
debugPrint("commited", commited)
}
success?(commited)
debugPrint("snap", snap?.value ?? "")
})
}
}
private func addEventToUserList(_ event: EventModel, timestamp: Double, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.main.async {
guard let userID = RealmManager().getCurrentUser()?.id else { return }
DispatchQueue.global(qos: .background).async {
let ref = Database.database().reference().child(self.MainPath.userLikedEvents.rawValue).child(userID).child(event.id)
let eventUserLike = EventUserLikeModel(eventID: event.id, systemInfo: event.systemInfo, dateInfo: event.dateProperties, systemTimestamp: timestamp)
let json = eventUserLike.toJSON()
ref.setValue(json, withCompletionBlock: { (error, ref) in
if let _error = error {
fail?(_error)
} else {
success?()
}
})
}
}
}
private func addUserToEventUsersList(_ eventID: String, timestamp: Double, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.main.async {
guard let userID = RealmManager().getCurrentUser()?.id else { return }
DispatchQueue.global(qos: .background).async {
let ref = Database.database().reference().child(self.MainPath.eventLikedUsers.rawValue).child(eventID).child(userID)
let json = ["userID" : userID, "timestamp" : timestamp] as [String : Any]
ref.setValue(json, withCompletionBlock: { (error, ref) in
if let _error = error {
fail?(_error)
} else {
success?()
}
})
}
}
}
}
// MARK: - Dislikes' functions
extension EventsLikeManager {
private func dislikeAction(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.global(qos: .background).async {
var commonError: Error?
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
self.likeNumber(event.id, isLike: false, success: { (isCommited) in
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.enter()
self.removeEventFromUserList(event.id, success: {
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.enter()
self.removeUserFromEventUsersList(event.id, success: {
dispatchGroup.leave()
}, fail: { (error) in
commonError = error
dispatchGroup.leave()
})
dispatchGroup.notify(queue: .main, execute: {
self.checkSystemEventQueue(event)
if let error = commonError {
fail?(error)
} else {
success?()
}
FirebasePerformanceManager.shared.likeDislikeAction(false)
})
}
}
private func removeEventFromUserList(_ eventID: String, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.main.async {
guard let currentUserID = RealmManager().getCurrentUser()?.id else { return }
DispatchQueue.global(qos: .background).async {
let ref = Database.database().reference().child(self.MainPath.userLikedEvents.rawValue).child(currentUserID).child(eventID)
ref.removeValue(completionBlock: { (error, ref) in
if let _error = error {
fail?(_error)
} else {
success?()
}
})
}
}
}
private func removeUserFromEventUsersList(_ eventID: String, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.main.async {
guard let userID = RealmManager().getCurrentUser()?.id else { return }
DispatchQueue.global(qos: .background).async {
let ref = Database.database().reference().child(self.MainPath.eventLikedUsers.rawValue).child(eventID).child(userID)
ref.removeValue(completionBlock: { (error, ref) in
if let _error = error {
fail?(_error)
} else {
success?()
}
})
}
}
}
}
// MARK: - Check events
extension EventsLikeManager {
private func userLikedEvent(_ eventID: String, notExists: (() -> Void)?, success: ((_ userLike: EventUserLikeModel) -> Void)?, fail: ((_ error: Error) -> Void)?) {
DispatchQueue.main.async {
guard let currentUserID = RealmManager().getCurrentUser()?.id else { return }
DispatchQueue.global(qos: .background).async {
let userLikedEventRef = Database.database().reference().child(self.MainPath.userLikedEvents.rawValue).child(currentUserID).child(eventID)
userLikedEventRef.observeSingleEvent(of: .value, with: { (snap) in
guard snap.exists() else {
notExists?()
return
}
guard let json = snap.value as? [String : Any] else { return }
guard let likedEvent = Mapper<EventUserLikeModel>().map(JSON: json) else { return }
success?(likedEvent)
}, withCancel: { (error) in
fail?(error)
})
}
}
}
}
// MARK: - Like Actions Helpers
extension EventsLikeManager {
private func getEventbriteAdditionalInfo(_ event: EventModel, success: (() -> Void)?, fail: ((_ error: Error) -> Void)?) {
let eventbriteAPIManager = EventbriteAPIManager()
eventbriteAPIManager.getAdditionalInfo(event, success: { (updatedEvent) in
self.eventLikeOutsourceAction(updatedEvent, success: success, fail: fail)
}, fail: fail)
}
}
// MARK: - System
extension EventsLikeManager {
private func newSystemEvent(_ event: EventModel) -> Bool {
let timestamp = Date().currentTimestamp
if dict[event.id] == nil {
dict[event.id] = [EventSystemLikeDislikeModel(timestamp: timestamp)]
} else if dict[event.id]?.count == 0 {
dict[event.id] = [EventSystemLikeDislikeModel(timestamp: timestamp)]
} else if var systemEvents = dict[event.id], systemEvents.count > 0 {
debugPrint("systemEvents", systemEvents.count)
let systemEvent = EventSystemLikeDislikeModel(timestamp: timestamp)
systemEvents.append(systemEvent)
dict[event.id] = systemEvents
return false
}
return true
}
private func checkSystemEventQueue(_ event: EventModel) {
systemQueue.sync {
guard var array = dict[event.id] else { return }
guard array.first != nil else { return }
array.removeFirst()
debugPrint("checkSystemEventQueue array.count", array.count)
if array.count > 0 {
dict[event.id] = array
} else {
dict[event.id] = nil
return
}
_likeEvents(event, success: nil, fail: nil)
}
}
}
关于ios - Firebase 喜欢/不喜欢系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47792315/
IO 设备如何知道属于它的内存中的值在memory mapped IO 中发生了变化? ? 例如,假设内存地址 0 专用于保存 VGA 设备的背景颜色。当我们更改 memory[0] 中的值时,VGA
我目前正在开发一个使用Facebook sdk登录(通过FBLoginView)的iOS应用。 一切正常,除了那些拥有较旧版本的facebook的人。 当他们按下“使用Facebook登录”按钮时,他
假设我有: this - is an - example - with some - dashesNSRange将使用`rangeOfString:@“-”拾取“-”的第一个实例,但是如果我只想要最后
Card.io SDK提供以下详细信息: 卡号,有效期,月份,年份,CVV和邮政编码。 如何从此SDK获取国家名称。 - (void)userDidProvideCreditCardInfo:(Car
iOS 应用程序如何从网络服务下载图片并在安装过程中将它们安装到用户的 iOS 设备上?可能吗? 最佳答案 您无法控制应用在用户设备上的安装,因此无法在安装过程中下载其他数据。 只需在安装后首次启动应
我曾经开发过一款企业版 iOS 产品,我们公司曾将其出售给大型企业,供他们的员工使用。 该应用程序通过 AppStore 提供,企业用户获得了公司特定的配置文件(包含应用程序配置文件)以启用他们有权使
我正在尝试将 Card.io SDK 集成到我的 iOS 应用程序中。我想为 CardIO ui 做一个简单的本地化,如更改取消按钮标题或“在此保留信用卡”提示文本。 我在 github 上找到了这个
我正在使用 CardIOView 和 CardIOViewDelegate 类,没有可以设置为 YES 的 BOOL 来扫描 collectCardholderName。我可以看到它在 CardIOP
我有一个集成了通话工具包的 voip 应用程序。每次我从我的 voip 应用程序调用时,都会在 native 电话应用程序中创建一个新的最近通话记录。我在 voip 应用程序中也有自定义联系人(电话应
iOS 应用程序如何知道应用程序打开时屏幕上是否已经有键盘?应用程序运行后,它可以接收键盘显示/隐藏通知。但是,如果应用程序在分屏模式下作为辅助应用程序打开,而主应用程序已经显示键盘,则辅助应用程序不
我在模拟器中收到以下错误: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
如 Apple 文档所示,可以通过 EAAccessory Framework 与经过认证的配件(由 Apple 认证)进行通信。但是我有点困惑,因为一些帖子告诉我它也可以通过 CoreBluetoo
尽管现在的调试器已经很不错了,但有时找出应用程序中正在发生的事情的最好方法仍然是古老的 NSLog。当您连接到计算机时,这样做很容易; Xcode 会帮助弹出日志查看器面板,然后就可以了。当您不在办公
在我的 iOS 应用程序中,我定义了一些兴趣点。其中一些有一个 Kontakt.io 信标的名称,它绑定(bind)到一个特定的 PoI(我的意思是通常贴在信标标签上的名称)。现在我想在附近发现信标,
我正在为警报提示创建一个 trigger.io 插件。尝试从警报提示返回数据。这是我的代码: // Prompt + (void)show_prompt:(ForgeTask*)task{
您好,我是 Apple iOS 的新手。我阅读并搜索了很多关于推送通知的文章,但我没有发现任何关于 APNS 从 io4 到 ios 6 的新更新的信息。任何人都可以向我提供 APNS 如何在 ios
UITabBar 的高度似乎在 iOS 7 和 8/9/10/11 之间发生了变化。我发布这个问题是为了让其他人轻松找到答案。 那么:在 iPhone 和 iPad 上的 iOS 8/9/10/11
我想我可以针对不同的 iOS 版本使用不同的 Storyboard。 由于 UI 的差异,我将创建下一个 Storyboard: Main_iPhone.storyboard Main_iPad.st
我正在写一些东西,我将使用设备的 iTunes 库中的一部分音轨来覆盖 2 个视频的组合,例如: AVMutableComposition* mixComposition = [[AVMutableC
我创建了一个简单的 iOS 程序,可以顺利编译并在 iPad 模拟器上运行良好。当我告诉 XCode 4 使用我连接的 iPad 设备时,无法编译相同的程序。问题似乎是当我尝试使用附加的 iPad 时
我是一名优秀的程序员,十分优秀!