- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图在我的应用程序中实现 JSQMesages,但是,我不明白为什么当我按下发送按钮时所有消息都消失了。我一步一步来,无法弄清楚,当聊天最初加载时,一切都在那里。但是发送按钮做了什么让一切都消失了?
有什么想法吗?
//
// JSQMessagesViewController.swift
// ACSS
//
// Created by Trever on 10/21/15.
// Copyright © 2015 trever.me. All rights reserved.
//
import UIKit
class MessagesViewController: JSQMessagesViewController {
// Refresh Messages
var timer : NSTimer!
// Don't double load!
var isLoading = false
// ID for this chatroom. Can have mutliple users
var chatroom = ""
// Currently only set up for two people
var currentUser : TradeUser?
var otherUser : PFUser?
//Value collection so don't double load too much
var avatars = [String:JSQMessagesAvatarImage]()
//Array of messages
var messages = [JSQMessage]()
//Collection of users
var users = [String : PFObject]()
// Chat bubbles for conversation
var outgoingBubbleImageView : JSQMessagesBubbleImage!
var incomingBubbleImageView : JSQMessagesBubbleImage!
override func viewDidLoad() {
super.viewDidLoad()
// Create a chatroom for each pair. Same for both
// Smaller ID first
self.senderId = TradeUser.currentUser()?.objectId
self.chatroom = currentUser!.objectId > otherUser!.objectId ?
"\(currentUser!.objectId!)-\(otherUser!.objectId!)" :
"\(otherUser!.objectId!)-\(currentUser!.objectId!)"
//Setup chat bubbles
let bubbleFactory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = bubbleFactory.outgoingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleLightGrayColor())
incomingBubbleImageView = bubbleFactory.incomingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleBlueColor())
//Loading...
isLoading = false
self.loadMessages()
//Check for new messages every 5 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "loadMessages", userInfo: nil, repeats: true)
self.senderDisplayName = "test"
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.collectionView?.collectionViewLayout.springinessEnabled = true
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
// when they leave this screen, stop checking for messages
timer.invalidate()
}
func loadMessages() {
if !isLoading {
isLoading = true
let message_last = messages.last
//Fetch Messages
let query = TradeChat.query()!
query.whereKey("chatRoom", equalTo: chatroom)
//Time Base Pagination
if message_last != nil {
query.whereKey("createdAt", greaterThan: message_last!.date)
}
// Get senders ID
query.includeKey("sender")
//Show Messages in order
query.orderByAscending("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
for object in objects! {
// Go through each message and create a message for display
let tradeChat = object as! PFObject
let senderObject = tradeChat.objectForKey("sender") as! PFObject
let senderFirstName = senderObject.objectForKey("firstName") as! String
let createdAt = tradeChat.createdAt
let text = tradeChat.objectForKey("chatText") as! String
let message = JSQTextMessage(senderId: senderObject.objectId!, senderDisplayName: senderFirstName, date: createdAt, text: text)
self.messages.append(message)
print(self.messages.count)
//Chache the user object for later
self.users[senderObject.objectId!] = senderObject
}
if !objects!.isEmpty {
self.finishReceivingMessage()
}
}
self.isLoading = false
})
}
}
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: NSDate!) {
// When they hit send. Save the message
let tradeChat = TradeChat()
tradeChat.chatRoom = chatroom
tradeChat.sender = TradeUser.currentUser()!
tradeChat.chatText = text
tradeChat.saveInBackgroundWithBlock { (succeeded, error) -> Void in
if error == nil {
JSQSystemSoundPlayer.jsq_playMessageSentSound()
self.loadMessages()
}
}
self.finishSendingMessage()
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item]
if message.senderId == self.senderId {
return outgoingBubbleImageView
} else {
return incomingBubbleImageView
}
}
override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
let message = messages[indexPath.item]
if self.avatars[message.senderId] == nil {
var imageView = JSQMessagesAvatarImage(placeholder: UIImage(named: "profile"))
self.avatars[message.senderId] = imageView
let user = users[message.senderId]!
print(user)
var parseAvatar = PFFile()
var imageQuery = TradeUser.query()!
imageQuery.whereKey("objectId", equalTo: user.objectId!)
imageQuery.limit = 1
imageQuery.findObjectsInBackgroundWithBlock({ (images: [AnyObject]?, error: NSError?) -> Void in
if imageQuery.countObjects() == 0 {
return
} else {
for image in images! {
if image.objectForKey("profileImage") == nil {
return
} else {
let userPic = image.objectForKey("profileImage") as! PFFile
userPic.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
let image = UIImage(data: imageData!)
imageView.avatarImage = JSQMessagesAvatarImageFactory.circularAvatarImage(UIImage(data: imageData!), withDiameter: 30)
}
})
}
}
}
})
// Reload entire table now that the avatar is downloaded
self.collectionView?.reloadData()
}
return self.avatars[message.senderId]
}
override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
// Show the name every once and a while
let message = messages[indexPath.item]
if message.senderId == self.senderId {
return nil
}
if indexPath.item - 1 > 0 {
let prevMessage = messages[indexPath.item - 1]
if prevMessage.senderId == message.senderId {
return nil
}
}
let firstName = otherUser?.objectForKey("firstName") as! String
return NSAttributedString(string: firstName)
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("Found \(messages.count) messages")
return messages.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// Grab the cell were about to show
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell
//Customize it some
let message = messages[indexPath.item]
if message.senderId == self.senderId {
cell.textView?.textColor = UIColor.blackColor()
} else {
cell.textView?.textColor = UIColor.whiteColor()
}
return cell
}
override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForCellTopLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
// If were going to show the date/time, give it some height
if indexPath.item % 3 == 0 {
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
return 0.0
}
override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
let message = messages[indexPath.item]
if message.senderId == self.senderId {
return 0.0
}
if indexPath.item - 1 > 0 {
let previousMessage = messages[indexPath.item - 1]
if previousMessage.senderId == message.senderId {
return 0.0
}
}
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
// more height logic
return 0.0
}
override func collectionView(collectionView: JSQMessagesCollectionView!, header headerView: JSQMessagesLoadEarlierHeaderView!, didTapLoadEarlierMessagesButton sender: UIButton!) {
print("tapped load earlier messages - need implementation")
}
}
最佳答案
我认为您的问题在于您没有在本地保存对话的对话对象。因此,当您按下 send
消息时,您正在发布一条消息进行解析,然后在后台线程中请求对话中的所有消息。
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
for object in objects! {
// Go through each message and create a message for display
let tradeChat = object as! PFObject
let senderObject = tradeChat.objectForKey("sender") as! PFObject
let senderFirstName = senderObject.objectForKey("firstName") as! String
let createdAt = tradeChat.createdAt
let text = tradeChat.objectForKey("chatText") as! String
let message = JSQTextMessage(senderId: senderObject.objectId!, senderDisplayName: senderFirstName, date: createdAt, text: text)
self.messages.append(message)
print(self.messages.count)
//Chache the user object for later
self.users[senderObject.objectId!] = senderObject
}
if !objects!.isEmpty {
self.finishReceivingMessage()
}
}
因为这是在后台线程上,UI
不会更新,因为它在主线程上。如果你有一个观察者或一个完成的闭包,然后调用你的 Collection View 在下载完所有内容后重新加载它可能会解决你的问题。
或者您可以有一个对话对象,当您按下发送时,您可以将它添加到本地的对话对象并将其发布到您的后端。然后在 View 上确实加载了你只需从后端提取对话并将其保存到本地副本并从那里显示它。您将拥有一个瞬时 UI
,如果消息发送失败,您可以警告用户并提示他们再次发送。
关于ios - JSQMessages 发送后空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33380686/
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 时
我是一名优秀的程序员,十分优秀!