objective-cuitableviewcore-datamanagedobjectcontext

Core Data: Modifying a Managed Object propagates to the rest of the UITableView records


I am in the process of writing a Master/Detail CoreData RSS reader for the fun of it.

I use the following entities: Category 1->n Feed 0->n Post

So in the left Pane of my UISplitView, there are the Feeds grouped by Category. Choosing a Feed will fetch, then display its Posts in the right pane.

The right pane also contains a UITableView which uses 2 sorts of prototype cells: read and unread.

read and unread depends upon the property (NSDate *)read of the corresponding Post ManagedObject: if it's nil, then it's to be displayed using an unread prototype cell.

Here's the code for the cellForRowAtIndexPath method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *feedTableIdentifier = @"unread";
    Post *thepost = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSDate *tmpDate=[NSDate date];
    if (thepost.read) {
        tmpDate=thepost.read;
        feedTableIdentifier = @"read";
    } else if (thepost.date) {
        tmpDate=thepost.date;
    }
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:feedTableIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:feedTableIdentifier];
    }
    ((UILabel *)[cell viewWithTag:1]).text = thepost.title;
    NSDateFormatter *df=[[NSDateFormatter alloc] init];
    df.dateFormat = @"EEEE, MMMM d, YYYY";
    ((UILabel *)[cell viewWithTag:2]).text = [df stringFromDate:tmpDate];
    ((UILabel *)[cell viewWithTag:3]).text = [self flattenHTML:thepost.excerpt];
    return cell;
}

Now, whenever I select a Post cell, I follow a segue which push a WebView pane onto the right pane. This WebView shows the contents of the relevant Post.url page. In the same time, I will edit the current Managed Object read property which I will set to the current NSDate. I will then save the ManagedObjectContext and refetch the right pane's Feeds to reflect the new format:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    PostDetailController *webController = [[PostDetailController alloc] init];

    if ([[segue identifier] isEqualToString:@"ShowWebLink"]) {
        webController = [segue destinationViewController];
        webController.urlstr = ((Post *)sender).url;
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Post *post=[self.fetchedResultsController objectAtIndexPath:indexPath];
    [self performSegueWithIdentifier:@"ShowWebLink" sender:post];
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    post.read = [NSDate date];
    NSError *error;
    if (![self.managedObjectContext save:&error])
    {
        NSLog(@"[didSelectRowAtIndexPath] Error saving context: %@", error);
    }
    [self refetch];
}

Now, here's my problem: When I pop the UIWebView and come back to the Feed list, the taped Post cell and all the following cells are now displayed as read the first time. The second time, all the cells in the UITableView are shown as read.

Could anybody tell me what I am doing wrong here? I would like only the selected object to be marked as read...

Thanks in advance for your help.

EDIT:

Could it come from this line in the didSelectRowAtIndexPath method?

post.read = [NSDate date];

Should I replace it with:

[post setValue:[NSDate date] forKey:@"read”];

I am still confused by the dot notation vs setValue...

EDIT 2:

Nope :( Just did the test.


Solution

  • Solved.

    The other data were not modified. I changed the cellForRowAtIndexPathmethod the following way:

    WAS

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *feedTableIdentifier = @"unread";
        Post *thepost = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSDate *tmpDate=[NSDate date];
        if (thepost.read) {
            tmpDate=thepost.read;
            feedTableIdentifier = @"read";
        } else if (thepost.date) {
            tmpDate=thepost.date;
        }
    

    IS

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *feedTableIdentifier = @"unread";
        Post *thepost = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSDate *tmpDate=[NSDate date];
        if (thepost.read) {
            tmpDate=thepost.read;
            feedTableIdentifier = @"read";
        } else if (thepost.date) {
            tmpDate=thepost.date;
            feedTableIdentifier = @"unread";
        }
    

    The staticvariable was affecting the other rows...