Question

I am trying to implement a chat feature in my application, using Realm.io as an internal database to store the chat messages, and PubNub to send and receive messages. I have ChatSessions, which define the channels that messages are sent over, and ChatMessages, which represent the messages themselves, and hold references to the text of the message, the date the message was sent, the name of the sender of the message, and the ChatSession that the message is a part of.

In the following code, I am initializing a ChatMessage from a PNMessage received across the channel, with all fields being specified. The issue I am having is that when Realm goes to write the message to the database, the session field of the ChatMessage is set to nil, despite that fact that right before the write method is called, the session field has a valid ChatSession specified.

- (void)createChatMessageFromMessage:(PNMessage *)message
{
    NSDictionary *msgDict = message.message;
    ChatMessage *chatMessage = [[ChatMessage alloc] init];
    chatMessage.text = [msgDict objectForKey:@"text"];
    chatMessage.dateSent = [NSDate dateWithTimeIntervalSinceReferenceDate:[[msgDict objectForKey:@"dateSent"] floatValue]];
    chatMessage.sender = [msgDict objectForKey:@"sender"];
    NSPredicate *sessionPredicate = [NSPredicate predicateWithFormat:@"sessionName = %@", [msgDict objectForKey:@"session"]];
    RLMArray *matches = [ChatSession objectsWithPredicate:sessionPredicate];
    if ([matches count] == 1) {
        chatMessage.session = [matches firstObject];
        NSLog(@"Added chatMessage with session name: %@", chatMessage.session.sessionName);
    } else {
        NSLog(@"Error: ChatSession with name %@ not found in db.", [msgDict objectForKey:@"session"]);
        return;
    }
    [NSThread detachNewThreadSelector:@selector(writeToDefaultRealm:) toTarget:self  withObject:chatMessage];
}

#pragma mark - Saving to Realm

- (void)writeToDefaultRealm:(RLMObject *)object
{
    RLMRealm *defaultRealm = [RLMRealm defaultRealm];
    [defaultRealm beginWriteTransaction];
    [defaultRealm addObject:object];
    if ([object isKindOfClass:[ChatMessage class]]) {
        [((ChatMessage *)object).session.messages addObject:object];
        NSLog(@"Wrtiting message with text: %@ with session name: %@", ((ChatMessage *)object).text, ((ChatMessage *)object).session.sessionName);
    } else {
        NSLog(@"Writing session with name: %@", ((ChatSession *)object).sessionName);
    }
    [defaultRealm commitWriteTransaction];
}

The NSLog right after setting chatMessage.session correctly logs what I want. The chatMessage has the correct session name. However, the NSLog within writeToDefaultRealm: correctly logs the message text, but logs a nil value for session.sessionName.

Does anyone know why this session field is being set to nil? Thank you

EDIT

ChatMessage.h

#import <Realm/Realm.h>

@class ChatSession;

@interface ChatMessage : RLMObject
// Add properties here to define the model
@property NSString *text;
@property NSDate *dateSent;
@property NSString *sender;
@property ChatSession *session;

@end

// This protocol enables typed collections. i.e.:
// RLMArray<ChatMessage>
RLM_ARRAY_TYPE(ChatMessage)

ChatSession.h

#import "ChatMessage.h"
#import <Realm/Realm.h>

@interface ChatSession : RLMObject

// Add properties here to define the model
@property NSDate *dateOpened;
@property NSDate *dateUpdated;
@property NSString *sessionName;
@property NSString *myAlias;
@property NSString *theirAlias;
@property RLMArray<ChatMessage> *messages;

@end

// This protocol enables typed collections. i.e.:
// RLMArray<ChatSession>
RLM_ARRAY_TYPE(ChatSession)
Was it helpful?

Solution

Realm doesn't currently support assigning to an RLMObject property outside of a write transaction. So when you do chatMessage.session = [matches firstObject];, because session is an RLMObject property (ChatSession), this must be done in a write transaction. Here's a possible solution:

- (void)createChatMessageFromMessage:(PNMessage *)message
{
    NSDictionary *msgDict = message.message;
    ChatMessage *chatMessage = [[ChatMessage alloc] init];
    chatMessage.text = [msgDict objectForKey:@"text"];
    chatMessage.dateSent = [NSDate dateWithTimeIntervalSinceReferenceDate:[[msgDict objectForKey:@"dateSent"] floatValue]];
    chatMessage.sender = [msgDict objectForKey:@"sender"];
    NSPredicate *sessionPredicate = [NSPredicate predicateWithFormat:@"sessionName = %@", [msgDict objectForKey:@"session"]];
    RLMArray *matches = [ChatSession objectsWithPredicate:sessionPredicate];
    if ([matches count] == 1) {
        RLMRealm *defaultRealm = [RLMRealm defaultRealm];
        [defaultRealm beginWriteTransaction];
        chatMessage.session = [matches firstObject];
        [chatMessage.session.messages addObject:chatMessage];
        [defaultRealm addObject:chatMessage];
        [defaultRealm commitWriteTransaction];
        NSLog(@"Added chatMessage with session name: %@", chatMessage.session.sessionName);
    } else {
        NSLog(@"Error: ChatSession with name %@ not found in db.", [msgDict objectForKey:@"session"]);
        return;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top