UILabel在自定义UITableView单元格不更新与核心数据更改 [英] UILabel in custom UITableView cell not updating with Core Data change

查看:193
本文介绍了UILabel在自定义UITableView单元格不更新与核心数据更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试建立一个游戏得分应用程序,利用自定义表格单元格与播放器的照片,名称,按钮等等。直接在桌面的自定义单元格中的添加/减少按钮,击中我的保存方法,并将其存储回特定用户的Core Data中。

I'm attempting to build a game scoring app that utilizes a custom table cell with player photos, names, buttons etc... There are add/subtract buttons directly in the custom cell of the tableview that are hitting my save method, and it's storing it back in Core Data for that specific user.

问题是屏幕上的分数没有更新和反映变化。保存动作到Core Data完成后,我调用 [self.tableView reloadData]; ...什么都没有。但是,如果我重新启动应用程序,则会显示分数变化(对于我点击的任何玩家)。

The problem is with the on-screen score not updating and reflecting the change. After the save action to Core Data is complete, I'm calling the [self.tableView reloadData];... nothing. However, if I restart the app, then the change in score (for any of the players I've clicked on), appears.

也许我更难

想法/评论?
提前感谢一个负载。
: - )

Thoughts / comments? Thanks a load in advance. :-)

对不起,如果这是过度的,但这是我的实现文件的大部分:

Sorry if this is overkill, but here is the majority of my implementation file:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self resetViews];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    [context setUndoManager:nil];
    _managedObjectContext = context;

    self.tableView.delegate = self;

    [self setNeedsStatusBarAppearanceUpdate];
}


-(void)resetViews {

    NSLog(@"\n\n\nresetViews()");

    [self setupFetchedResultsController];
    [self.tableView reloadData];
    [self.view setNeedsDisplay];
}

- (void)setupFetchedResultsController {

    NSString *entityName = @"Players";
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

    request.sortDescriptors = [NSArray arrayWithObject:
                               [NSSortDescriptor
                                sortDescriptorWithKey:@"playerName"
                                ascending:YES
                                selector:@selector(localizedCaseInsensitiveCompare:)]];

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:nil
                                                                                   cacheName:nil];

    NSError *error;
    NSArray *results = [_managedObjectContext executeFetchRequest:request error:&error];
    _playerArray = [[NSMutableArray alloc]initWithArray:results];

    NSLog(@"_playerArray count: %i", [_playerArray count]);
    NSLog(@"\n");
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _playerArray.count;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *cellIdentifier = @"playerCell";
    ScoringCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    // Configure the cell...
    Players *player_info = [_playerArray objectAtIndex:indexPath.row];

    NSSet *score = player_info.scores;

    for (Scoring *perObj in score){
        cell.lblPlayerScore.text = [perObj.score stringValue];
        NSLog(@"\n\n\n score for %@: %@", player_info.playerName, perObj.score);
    }

    cell.lblPlayerName.text = player_info.playerName;
    cell.lblPlayerNickName.text = player_info.playerNickName;
    cell.btnIncreaseScore.tag = indexPath.row;
    cell.btnDecreaseScore.tag = indexPath.row;
    cell.imgPlayerPhoto.image = [UIImage imageNamed:@"tmp_playerImage"];

    return cell;
}


- (IBAction)increaseScore:(id)sender {

    NSLog(@"PageContentViewController: increaseScore()");
    UIButton* btn=(UIButton*)sender;
    int selectedPlayerInt = btn.tag;
    //NSLog(@"Selected row is: %d",btn.tag);

    Players *player_info = [_playerArray objectAtIndex:selectedPlayerInt];
    [self updateRowScore:player_info:@"add"];
}

- (IBAction)decreaseScore:(id)sender {

    NSLog(@"PageContentView: decreaseScore()");
    UIButton* btn=(UIButton*)sender;
    int selectedPlayerInt = btn.tag;
    //NSLog(@"Selected row is: %d",btn.tag);

    Players *player_info = [_playerArray objectAtIndex:selectedPlayerInt];
    [self updateRowScore:player_info:@"subtract"];
}

-(void)updateRowScore: (Players *)player_info :(NSString *)modifier {

    NSLog(@"\n\nupdateRowScore()");
    NSLog(@"Update score (%@) for: %@\n", modifier, player_info.playerName);

    NSArray *scoreDataArray;

    if ([self playerScoreCount:player_info] == 0) {

        // NEW score... we've never scored before.
        Scoring *scoring_data = [NSEntityDescription
                                 insertNewObjectForEntityForName:@"Scoring"
                                 inManagedObjectContext:_managedObjectContext];

        //Since this is the first score, always set it to 1
        scoring_data.score = [NSNumber numberWithInt:1];
        scoring_data.holeNumber = [NSNumber numberWithInt:_pageIndex];
        scoring_data.scoredBy = player_info;

    } else {

        //Update existing player score..
        NSError *error = nil;
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

        NSEntityDescription *BEntity = [NSEntityDescription entityForName:@"Scoring" inManagedObjectContext:_managedObjectContext];
        [fetchRequest setEntity:BEntity];

        NSPredicate *predicate = [NSPredicate
                                  predicateWithFormat:@"(scoredBy = %@)", [player_info objectID]];
        [fetchRequest setPredicate:predicate];

        NSArray *results = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
        scoreDataArray = [[NSMutableArray alloc]initWithArray:results];

        Scoring *score_update = [scoreDataArray objectAtIndex:0];
        int currentScore = [score_update.score intValue];
        NSLog(@"current score: %d", currentScore);

        if ([modifier  isEqual: @"add"]) {
            currentScore++;
        } else {

            // Don't allow negative scores.
            if (currentScore >= 1) {
                currentScore--;
            } else {
                currentScore = 0;
            }
        }

        NSLog(@"NEW score: %d", currentScore);
        score_update.score = [NSNumber numberWithInt:currentScore];
    }


    // write to database
    [self.managedObjectContext save:nil];

    [self resetViews];
}








UPDATE:
感谢提示bbarnhart ...我已经阅读过那个职位之前,并已用于一个基础从我开始。决定更进一步,使用更多的Ray Wenderlich示例重构一大堆代码。


UPDATE: Thanks for the tip bbarnhart... I had read through that post before and had used that for a basis from which I had started. Decided to take it a step further and refactor a chunk of code using more of the Ray Wenderlich example.

我已经看到了一些改进的记录,并报告回来通过NSLog的...但是视图仍然没有改变。

I've seen some improvements to what's being recorded, and reported back through the NSLog's... but the view just still is not changing.

这个动作是增加分数,然后我重置单元格使用 [self configureCell:cell atIndexPath:path]; 在那里...负责发送文本到显示的方法... NSLog显示 2014- 12-04 22:40:40.199 appName [7153:150248] Tim:4 的分数显示仍然只显示3.

The action is increasing the score, and then I'm resetting the cell using [self configureCell:cell atIndexPath:path]; In there... the method that is responsible for sending text to the display... the NSLog is showing 2014-12-04 22:40:40.199 appName[7153:150248] Score for Tim: 4 when the display still only shows 3.

I知道这是一些愚蠢的菜鸟移动...我只是做一些死的错,我不能弄清楚。以下是修改后的程式码片段。

I know this is some stupid rookie move... I'm just doing something dead wrong that I can't figure out. Here's a snippet of the amended code.

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"Players"
                                   inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"playerName" ascending:YES];

    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:_managedObjectContext
                                        sectionNameKeyPath:nil
                                        cacheName:@"Root"];

    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    NSError *error;
    NSArray *results = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
    _playerArray = [[NSMutableArray alloc]initWithArray:results];
    NSLog(@"_playerArray count: %i", [_playerArray count]);

    return _fetchedResultsController;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {       
    id  sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *cellIdentifier = @"playerCell";
    ScoringCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[ScoringCell alloc] initWithStyle:UITableViewCellStyleSubtitle 
                                   reuseIdentifier:cellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(ScoringCell *)cell atIndexPath:(NSIndexPath *)indexPath {

    Players *player_info = [_fetchedResultsController objectAtIndexPath:indexPath];
    NSSet *scoreSet = player_info.scores;

    NSString *cell_score;   
    for (Scoring *scoreObj in scoreSet) {
        cell_score = [scoreObj.score stringValue];
    }

    NSLog(@"Score for %@: %@", player_info.playerName, cell_score);

    if (cell_score != nil) {
        cell.lblPlayerScore.text = cell_score;
    }

    cell.lblPlayerName.text = player_info.playerName;
    cell.lblPlayerNickName.text = player_info.playerNickName;
    cell.btnIncreaseScore.tag = indexPath.row;
    cell.btnDecreaseScore.tag = indexPath.row;
    cell.imgPlayerPhoto.image = [UIImage imageNamed:@"demo_playerb"];

    [self resetViews];
    NSLog(@"\n");
}

- (IBAction)increaseScore:(id)sender {

    NSLog(@"PageContentViewController: increaseScore()");
    UIButton *senderButton = (UIButton *)sender;
    int selectedPlayerInt = senderButton.tag;
    NSIndexPath *path = [NSIndexPath indexPathForRow:senderButton.tag inSection:0];

    Players *player_info = [_playerArray objectAtIndex:selectedPlayerInt];
    [self updateRowScore:player_info:@"add":selectedPlayerInt:path];
}

-(void)updateRowScore:(Players *)player_info :(NSString *)modifier :(int)selectedPlayerInt :(NSIndexPath *)path  {

    NSArray *scoreDataArray;
    if ([self playerScoreCount:player_info] == 0) {

        // NEW score... we've never scored before.
        Scoring *scoring_data = [NSEntityDescription
                                 insertNewObjectForEntityForName:@"Scoring"
                                 inManagedObjectContext:_managedObjectContext];

        //Since this is the first score, always set it to 1
        scoring_data.score = [NSNumber numberWithInt:1];
        scoring_data.holeNumber = [NSNumber numberWithInt:_pageIndex];
        scoring_data.scoredBy = player_info;

    } else {

        //Update existing player score..

        NSError *error = nil;
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

        NSEntityDescription *BEntity = [NSEntityDescription entityForName:@"Scoring" 
                                  inManagedObjectContext:_managedObjectContext];
        [fetchRequest setEntity:BEntity];

        NSPredicate *predicate = [NSPredicate
                                  predicateWithFormat:@"(scoredBy = %@)", [player_info objectID]];
        [fetchRequest setPredicate:predicate];

        NSArray *results = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
        scoreDataArray = [[NSMutableArray alloc]initWithArray:results];

        Scoring *score_update = [scoreDataArray objectAtIndex:0];
        int currentScore = [score_update.score intValue];
        NSLog(@"current score: %d", currentScore);

        if ([modifier  isEqual: @"add"]) {

            currentScore++;
        } else {

            // Don't allow negative scores.
            if (currentScore >= 1) {
                currentScore--;
            } else {
                currentScore = 0;
            }
        }

        NSLog(@"NEW score: %d", currentScore);
        score_update.score = [NSNumber numberWithInt:currentScore];
    }


    // write to database
    [self.managedObjectContext save:nil];


    static NSString *cellIdentifier = @"playerCell";
    ScoringCell *cell = [_tableView dequeueReusableCellWithIdentifier:cellIdentifier];


    [self configureCell:cell atIndexPath:path]; 
    [self resetViews];  
}



----------



UPDATE:
我已经有一段时间了,因为我有机会重温,只是注意到一个新的问题,因为启用你的提示。当在列表中向下或向上滚动并超出正常边界时,tableview数据似乎会覆盖当前行上方或下方行的显示。奇怪...不知道这个动画Gif会显示在堆栈。下面是一个例子:

----------

UPDATE: Been awhile since I've had a chance to revisit, and just noticed a new problem since enabling your tips. When scrolling down or up in the list and pulling beyond the normal boundaries, the tableview data seems to overwrite the display for the row either above or below the current line. Weird... Not sure if this animated Gif will show up in Stack. Here's an example:

推荐答案

表视图不动态更新的主要原因是 NSFetchedResultsController 发生更改时通知的代表。您需要设置该委托, self.fetchedResultsController.delegate = self ,然后添加委托方法。

The main reason your table view is not updating dynamically is NSFetchedResultsController uses a delegate for notification when changes occur. You'll need to set that delegate, self.fetchedResultsController.delegate = self and then add the delegate methods.

以下是链接到示例使用 NSFetchedResultsController 管理 UITableView

更新

实现这些 NSFetchResultsController 委托方法以允许动态更新您的表。

Implement these NSFetchResultsController delegate methods to allow your table to be dynamically updated.

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath: (NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type

通常,这些方法包含用于更新表的样板代码,上面的链接。

Generally, these methods contain boilerplate code for updating your table which you will also find in the link above.

这篇关于UILabel在自定义UITableView单元格不更新与核心数据更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆