简体   繁体   中英

PubNub local messages duplicating?

For my pubnub chat app, I am storing some messages locally to keep it from using tons of wifi/data. It seems to work fine, but sometimes the last message is duplicated. Here is my saving,loading,reloading code.

#pragma mark - PubNub manager methods

- (NSString *)parseMessage:(id)message
{
    if ([message isKindOfClass:[NSDictionary class]]) {

        NSDictionary *messageAsDict = message;

        if ([[messageAsDict objectForKey:@"text"] isKindOfClass:[NSString class]]) {
            NSString *messageString = [messageAsDict objectForKey:@"text"];

            if (messageString || messageString.length > 0) {
                return messageString;
            } else {
                return @"Unable To Parse Message";
            }
        } else {
            return @"Unable To Parse Message";
        }
    } else if ([message isKindOfClass:[NSString class]]) {

        NSString *messageString = message;

        if (messageString.length > 0) {
            return messageString;
        } else {
            return @"Unable To Parse Message";
        }
    } else {
        return @"Unable To Parse Message";
    }
}

- (void)saveObjects
{
    NSError *error;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = [paths objectAtIndex:0];

    NSString *messagesDirectoryPath = [docDir stringByAppendingPathComponent:@"Messaging"];

    if (![[NSFileManager defaultManager] fileExistsAtPath:messagesDirectoryPath]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:messagesDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error];
    }

    NSString *messagesPath = [messagesDirectoryPath stringByAppendingPathComponent:messageFile];
    NSString *timeTokenPath = [messagesDirectoryPath stringByAppendingPathComponent:timeTokenFile];

    NSString *timeTokenString = [NSString stringWithFormat:@"%ld", (long)lastTimeToken];

    [messagesArray writeToFile:messagesPath atomically:YES];
    [timeTokenString writeToFile:timeTokenPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
}

- (void)loadObjects
{
    NSError *error;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = [paths objectAtIndex:0];

    NSString *messagesDirectoryPath = [docDir stringByAppendingPathComponent:@"Messaging"];

    NSString *messagesPath = [messagesDirectoryPath stringByAppendingPathComponent:messageFile];
    NSString *timeTokenPath = [messagesDirectoryPath stringByAppendingPathComponent:timeTokenFile];

    messagesArray = [NSMutableArray arrayWithContentsOfFile:messagesPath];

    if (!messagesArray) {
        messagesArray = [[NSMutableArray alloc] init];
        [self saveObjects];
    }

    NSString *timeTokenString = [NSString stringWithContentsOfFile:timeTokenPath encoding:NSUTF8StringEncoding error:&error];

    if (![timeTokenString isEqualToString:@""]) {
        lastTimeToken = [timeTokenString integerValue];
    } else {
        lastTimeToken = [self currentTimeToken];
        [self saveObjects];
    }
}

- (void)reloadMessages
{
    messagesArray = [[NSMutableArray alloc] init];

    //Get all the chats you missed
    [self.pnClient historyForChannel:kCHAT_CHANNEL withCompletion:^(PNHistoryResult *result, PNErrorStatus *status) {

        // Check whether request successfully completed or not.
        if (!status.isError) {

            // Handle downloaded history using:
            //   result.data.start - oldest message time stamp in response
            //   result.data.end - newest message time stamp in response
            //   result.data.messages - list of messages

            // Get messages

            for (id message in result.data.messages) {
                [messagesArray addObject:[self parseMessage:message]];
            }

            // Set timetoken

            lastTimeToken = [self parsePNTimeToken:result.data.end];

            // Save stuff

            [self saveObjects];

            dispatch_async(dispatch_get_main_queue(), ^{

                [self.messagesTable reloadData];

                [self scrollToBottom];
            });
        } else {
            // Request processing failed.

            UIAlertController *errorController = [UIAlertController alertControllerWithTitle:@"Error" message:@"Could not recieve messages" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];

            UIAlertAction *retryAction = [UIAlertAction actionWithTitle:@"Retry" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
                [status retry];
            }];
            [errorController addAction:cancelAction];
            [errorController addAction:retryAction];
            [self presentViewController:errorController animated:YES completion:nil];

        }
    }];
}

- (void)addMessage:(PNMessageResult *)message
{
    [messagesArray addObject:[self parseMessage:message.data.message]];
    lastTimeToken = [message.data.timetoken integerValue] + 1;
    [self saveObjects];
}

- (NSInteger)parsePNTimeToken:(NSNumber *)timeToken
{
    return trunc([timeToken integerValue] / pow(10, 7));
}

- (NSInteger)currentTimeToken
{
    return [[NSDate date] timeIntervalSince1970];
}

- (void)updateLostMessages
{
    [self.pnClient historyForChannel:kCHAT_CHANNEL start:[NSNumber numberWithInteger:lastTimeToken] end:[NSNumber numberWithInteger:[self currentTimeToken]] limit:NSIntegerMax withCompletion:^(PNHistoryResult *result, PNErrorStatus *status) {

        NSArray *tempResultArray = result.data.messages;

        for (id message in tempResultArray) {
            [messagesArray addObject:[self parseMessage:message]];
            NSLog(@"%@", [self parseMessage:message]);
        }

        lastTimeToken = [self currentTimeToken] + 1;

        [self saveObjects];

        [self loadObjects];

        dispatch_async(dispatch_get_main_queue(), ^{

            [self.messagesTable reloadData];
            [self scrollToBottom];

        });
    }];
}

These methods are pretty straightforward. the parseMessage: one takes a message from whatever and parses the text to be displayed. The saveObjects saves the timeToken and the messages to the disk, and load loads them. The timetoken methods just convert PN timetokens to a less precision format and get the current time token. The updateLostMessages gets all messages from the last messages timetoken to current, and to not get all the messages.

In viewDidLoad I call [self loadObjects] and then [self updateLostMessages] problem is that messages are duplicating! Help appreciated. Also, sorry for long code.

Haha, silly me. I just forgot a + 1 in the reload method. Well, for anyone who wants to use this code to locally store messages instead of getting all of them, here you go. This code stores a timetoken of the last message (+1), and gets all messages from x time token to now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM