ios - Swift iOS - 如何在 Firebase TransactionBlock 上放置计时器以防止它在特定时间段内增加
问题描述
每次不同的用户发布一些东西(比如说一种颜色)时,我都会得到他们发布的颜色、postID、他们的 userId、以秒为单位的日期以及该帖子被查看的次数。
不同的用户可以查看 tableView 并查看每个用户发布的每种颜色的不同单元格。
每次正在查看的用户点击didSelectRow
查看颜色的详细视图时,我都会运行一个Firebase TransactionBlock
增加views
计数属性以显示特定颜色/单元格被点击的次数。
例如,如果用户滚动一个 tableView 并看到一个 blueCell,则会在其上显示一个标签,上面写着views: 10(意味着它被查看了 10 次)。如果该用户再次按下该 blueCell ,则视图计数将显示views: 11。
问题是如果该用户反复按下该单元格,那么他们可以在几秒钟内增加该标签上的值count
。views
我如何跟踪用户点击的每个对象/单元格并在其上放置一个计时器,以便他们无法在views count
一个小时左右的时间内更新该特定对象的值?我有以秒为单位的日期和 postId,它们对每个对象都是唯一的。
基本上,如果用户在下午 12 点按下 blueCell,则与该特定单元格关联的对象的视图计数将上升到 11,但如果他们在下午 12 点至下午 1 点之间的任何时间再次按下它,它就不会上升。下午 1 点之后,如果他们再次按下它,该对象的观看次数将上升到 12?
我可以用来识别每个颜色对象的模型对象和属性:
class ColorClass{
var color: String?
var postID: String?
var userId: String?
var date: NSNumber?
var views: NSNumber? // keeps track of how many the post was viewed
}
TableView 的 didSelectRow:
// the current user who is pressing the cell
let currentUserID = Auth.auth().currentUser?.uid
var colors = [ColorClass]() // 500 model objects
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colors.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ColorsCell", for: indexPath) as! ColorsCell
cell.viewsLabel.text = colors[indexPath.row].views // I separately convert this from a NSNumber to a String
cell.colorLabel.text = colors[indexPath.row].color
return cell
}
// pressing the cell will increase the count on the object's views property
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let indexPath = tableView.indexPathForSelectedRow else { return }
// the userId on the object of the cell that was pressed
guard let userID = colors[indexPath.row].userId else { return }
guard let postID = colors[indexPath.row].postId else { return }
// make sure the current user can't update the views on their own post
if currentUserID != userID{
let viewsRef = databaseRef?.child(userID).child(postID).child("views")
viewsRef?.runTransactionBlock({
(currentData: MutableData) -> TransactionResult in
let newValue: Int
guard let existingValue = (currentData.value as? NSNumber)?.intValue else {
return TransactionResult.abort()
}
newValue = existingValue + 1
currentData.value = NSNumber(value: newValue)
return TransactionResult.success(withValue: currentData)
}, andCompletionBlock: {
(error, completion, snap) in
print(snap as Any)
if !completion{
print("The value wasn't able to update")
print(error?.localizedDescription as Any)
}else{
print("The value updated")
}
})
}
}
只是一个想法。
我考虑过创建另一个具有 currentUserID、postID 和 tappedTime 属性的对象。然后我会创建一个单例。每次按下单元格时,我都会将数据传递到对象中,然后将对象发送到单例中的数组。在那里我有一个 currentTime 属性。首先,我会检查 postID 是否在数组中,如果是,我会将 tappedTime 与 currentTime + 1 小时进行比较,以确定是否应该增加观看次数。我有一个调度异步计时器,1 小时后它会自动从阵列中清除。我不确定它有多实用。
解决方案
您可以创建一个typealias
由您正在填充单元格的任何对象组成,并Date
在视图控制器的顶部创建一个,如下所示:
typealias ColorLastSelected = (colorClass: ColorClass, timeSelected: Date)
然后,创建一个数组来存储ColorLastSelected
对象。
var selectedColors: [ColorLastSelected] = []
从那里,在 中didSelectRow
,您可以执行一个保护语句来检查一个对象是否包含在selectedColors
数组中。如果没有,那么做任何你必须做的事情,最后,初始化一个ColorLastSelected
对象并将其附加到selectedColors
数组中。
在保持selectedColors
最新方面,您可以在重复计时器上运行更新方法以删除ColorLastSelected
超过 1 小时的 s。或者,您可以selectedColors
在保护语句之前过滤数组以删除超过一个小时的内容。如果您要在视图控制器之间跳来跳去,您可能需要创建一个“保持活动状态”的单例,或者您可以将selectedColors
数组保存在某个地方
推荐阅读
- c# - 当 oject 不为空时,为什么我在搜索查询中收到 NullReferenceException
- reactjs - 如何使用 setState 回调函数进行条件函数调用
- regex - oracle regexp_like:使用 Perl 正则表达式与运算符等效
- c# - 有点像头文件,我可以在 C# 中分离一些定义吗?
- python - Pandas 突然无法打开 Excel 文件(在 OLE2 复合文档中找不到工作簿
- c# - 如何绑定多个输入字段,包括单选按钮以在.net核心中列出
- vba - 即使 IIF 条件状态不检查,空访问 VBA 的使用也无效
- swift - textfielddidbegin 编辑不更新标签
- swift - Swift date(byAdding:to:) 为 REPL 中的简单计算返回 nil
- php - 如何在我的PHP中一一删除相关数据?