【问题标题】:Using JSQMessagesViewController with Parse.com将 JSQMessagesViewController 与 Parse.com 一起使用
【发布时间】:2015-04-13 14:56:35
【问题描述】:

我遇到了一个看起来非常复杂且可自定义的库,对于任何想要内置消息传递系统的应用程序都非常有用。JSQMessagesViewController on Github。当我试图自己实现这个库时,我遇到了一些问题。一个我不太了解“协议”和“类”的术语(我对类有点了解)。第一个问题是我不能在 CollectionView 中使用 PFObjects,因为 JSQMessage 的实例需要通过大多数自定义方法传递。现在,我知道如何接收 PFObject 并从中获取属性,例如

self.eachMessage = [self.messages objectAtIndex:indexPath.row]; //each message
self.eachMessage[@"message"] //message from the PFObject
self.eachMessage[@"sender"] //sender from the PFObject

JSQMessage 类具有自定义属性,可以表示 PFObject 的属性,例如

JSQMessage *message = [[JSQMessage alloc] init]; //initialize it
message.senderId //could be the objectId of the user
message.senderDisplayName //the user's username
message.text //text of the message
message.date //time sent of the message

问题是,在自定义类 JSQMessage 中……所有这些属性都是只读的。我确信我可以进去改变它,这样我就可以将它们分配给我想要的东西,但这里一定有我遗漏的东西。我将在我的 .h 和 .m 文件中附加所有内容。 当我确实发送消息时,唯一通过的就是文本,我相信这是因为它来自 inputToolbar 上的 textView。

.h 文件

#import <UIKit/UIKit.h>
#import <JSQMessagesViewController/JSQMessages.h>
#import <Parse/Parse.h>
#import <JSQMessagesViewController/JSQMessagesBubbleImageFactory.h>


@interface ConvoViewController : JSQMessagesViewController 

@property (strong, nonatomic) NSMutableArray *messages;
@property (strong, nonatomic) PFUser *sender;
@property (strong, nonatomic) PFUser *receiver;
@property (strong, nonatomic) JSQMessage *eachMessage;
@property (strong, nonatomic) PFObject *aMessage;
@property (strong, nonatomic) JSQMessagesBubbleImageFactory *bubbleImage;

@end

.m 文件

- (void)viewDidLoad {
    [super viewDidLoad];
    //Color of the keyboard (Dark to match everything else)
    self.inputToolbar.contentView.textView.keyboardAppearance = UIKeyboardAppearanceDark;

    //Color the inputview background
    self.inputToolbar.backgroundColor = [UIColor colorWithWhite:0 alpha:0.9];

    //Delete the avatars appearing next to the messages
    self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
    self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;

    //Set the senderID
    self.senderId = self.sender.objectId;


}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];

    //Query for part of the messages
    PFQuery *messages1 = [PFQuery queryWithClassName:@"Messages"];
    [messages1 whereKey:@"sender" equalTo:self.sender];
    [messages1 whereKey:@"receiver" equalTo:self.receiver];

    //Query for other part of messages
    PFQuery *messages2 = [PFQuery queryWithClassName:@"Messages"];
    [messages2 whereKey:@"sender" equalTo:self.receiver];
    [messages2 whereKey:@"receiver" equalTo:self.sender];

    //Combine those queries
    PFQuery *allMessages = [PFQuery orQueryWithSubqueries:@[messages1, messages2]];
    [allMessages findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        self.messages = [objects mutableCopy];
        [self.collectionView reloadData];
    }];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


#pragma mark - Send Button
- (void)didPressSendButton:(UIButton *)button withMessageText:(NSString *)text senderId:(NSString *)senderId senderDisplayName:(NSString *)senderDisplayName date:(NSDate *)date {
    [JSQSystemSoundPlayer jsq_playMessageSentSound];

    JSQMessage *message = [[JSQMessage alloc] initWithSenderId:self.sender.objectId
                                             senderDisplayName:self.sender.username
                                                          date:[NSDate date]
                                                          text:text];

    [self.messages addObject:message];
    NSLog(@"%@", text);

    [self finishSendingMessageAnimated:YES];


}

#pragma mark - JSQMessages Data Source methods

- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
    //Return the actual message at each indexpath.row
    return [self.messages objectAtIndex:indexPath.row];
}

- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
    /**
     *  You may return nil here if you do not want bubbles.
     *  In this case, you should set the background color of your collection view cell's textView.
     *
     *  Otherwise, return your previously created bubble image data objects.
     */

    JSQMessage *message = [self.messages objectAtIndex:indexPath.item];
    if ([message.senderId isEqualToString:self.senderId]) {
        return [self.bubbleImage incomingMessagesBubbleImageWithColor:[UIColor orangeColor]];
    }

    return [self.bubbleImage outgoingMessagesBubbleImageWithColor:[UIColor grayColor]];
}



#pragma mark - Collection View

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    //Number of messages
    return self.messages.count;
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    //Number of sections
    return 1;
}


- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    //Creating or initial cell for the number of index paths (number of messages)
    JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];

    //Put our messages dictionaries into PFObject so we can put them into individual cells
    self.eachMessage = [self.messages objectAtIndex:indexPath.row];


    //Put the message object into the textView's text property
    cell.textView.text = self.eachMessage.text;

    //Setting the text color of the message bubble based upon the sender
    if ([self.eachMessage.senderId isEqualToString:self.senderId]) {
        cell.textView.textColor = [UIColor blackColor];
    } else {
        cell.textView.textColor = [UIColor whiteColor];
    }
    //Set the top label to the person who sent the message
    cell.cellTopLabel.text = [NSString stringWithFormat:@"@%@", self.eachMessage.senderId];

    //Format the bottom label to a readable date
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"MM/dd/yy h:mm a"];
    cell.cellBottomLabel.text = [dateFormatter stringFromDate:self.eachMessage.date];

    //If there is a link of some sorts in the message
    cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
                                          NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };

    //What we return into the collectionview
    return cell;

}

【问题讨论】:

  • @jsetting32 这是一个很好的答案。使用 Parse 完成所有这些工作就更有意义了,我实际上只需要更改所有不同的查询参数来满足我的要求,并以我想要的方式对其进行自定义。操作已经构建成我需要的代码非常容易。你应该把它作为答案,因为对于那些使用 Parse 作为后端的人来说,使用这个 GitHub 项目作为参考要容易得多
  • 很高兴我链接的回购帮助了你!我只有一个建议。进入推送通知。这将帮助您的应用成为“实时”聊天应用。由于链接的项目仅使用计时器来运行加载消息功能,因此它不是最佳的,例如每 5 秒加载一次消息。使用推送通知使其成为实时。因此,当其他用户向您发送消息时,应用程序会自动加载该消息。如果大家都想实现此功能并需要帮助,请随时添加评论。
  • 我已经这样做了,我的朋友。在我重建之前,我在我以前的应用程序版本上实现了推送。起初那是另一个谜,但经过反复试验和几个教程后,我想通了。我想学习的一件事是如何让用户点击通知,然后让它直接进入该特定视图控制器中的应用程序,甚至可能将其插入对话中。我看到了一些小事,比如让用户体验更加完整。
  • 啊太棒了!至于当用户滑动/点击通知时推送到关联的控制器,您可以查看 Parse 的 Anypic 示例。当用户发布照片时,人们会收到通知。然后,当点击通知时,应用程序会打开照片的详细控制器。因此,如果您需要有关如何执行此操作的指导,只需查看 parse anypic 应用程序委托实现。它真的帮助我理解了如何处理通知

标签: ios objective-c iphone parse-platform pfobject


【解决方案1】:

这是我的代码的一部分。整个文件很大,如果我分享这些文件,我的老板不会高兴的。 :-)

这是我在DemoMessagesViewController 中加载 DemoData 的方式:

self.demoData = [[DemoModelData alloc] init];

self.demoData.users = @{self.senderId:self.senderDisplayName,
                        self.targetUserId:self.targetUserName};

UIImage *tempImg = [HTTPServerKaDost fetchImageFromUrlString:userProfile.profilePicUrl]; //replace with your code to load image

JSQMessagesAvatarImage *srcImage = [JSQMessagesAvatarImageFactory
                                    avatarImageWithImage:tempImg
                                    diameter:kJSQMessagesCollectionViewAvatarSizeDefault];

tempImg = [HTTPServerKaDost fetchImageFromUrlString:self.targetUserImageFullUrl];

JSQMessagesAvatarImage *destImage = [JSQMessagesAvatarImageFactory
                                     avatarImageWithImage:tempImg
                                     diameter:kJSQMessagesCollectionViewAvatarSizeDefault];

self.demoData.avatars = @{self.senderId:srcImage,
                          self.targetUserId:destImage};

[self.demoData loadMessages];

loadMessages方法内(由我在DemoModelData类中添加),创建JSQMessage对象:

JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:[msgDict valueForKey:@"sender"]
                                     senderDisplayName:[msgDict valueForKey:@"fname"]
                                                  date:dateT
                                                  text:[msgDict valueForKey:@"data"]];

[self.messages addObject:msg];

任何时候你想刷新聊天视图,都可以在DemoMessagesViewController 内调用:

[self finishReceivingMessageAnimated:YES];
[self scrollToBottomAnimated:YES];

【讨论】:

  • 我想我对此有所了解。那么,您所做的只是将原始演示中的所有静态信息(更像是摆脱)更改为您(就您而言)从网站收集的动态信息? DemoModelData 类和 ViewController 中的所有内容都差不多吗?
  • 是的。多玩一下演示项目,你就会掌握它的窍门。
猜你喜欢
  • 2016-01-12
  • 1970-01-01
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多