【问题标题】:Check progress where is necessary UITableView在必要的地方检查进度 UITableView
【发布时间】:2015-03-27 09:22:46
【问题描述】:

我在保存UITableViewCell 的状态时遇到问题,不知道如何解决。希望有人可以帮助我。

解释: 服务器上有一个 API,我从中获取数据,然后将其存储在 NSMutableArray 中。数组的每个对象都包含属性ready,可以是10。所以我用这个数据填充UITableView没有问题,但不是每个数据对象都准备好了(即0),我需要在服务器上获得完成进度,然后在每个单元格中显示它是需要的。我在UITableViewCell 的动态原型中拥有UIProgressView,并在获得后设置进度。如果这样的“未准备好”对象只有一个,则没有问题。但是,如果有很多对象,我就无法显示进度并且我不明白为什么。

这是我的代码。

cellForRowAtIndexPath 方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"readyCell";
AVMMovieCell  *cell = [self.readyTable dequeueReusableCellWithIdentifier:CellIdentifier];
    // Configure the cell...
if (cell == nil) {
    cell = (AVMMovieCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
AVMFilmsStore *oneItem;
oneItem = [readyArray objectAtIndex:indexPath.row];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];

if (oneItem.ready==1){
    cell.progressLabel.hidden = YES;
    cell.progressLine.hidden = YES;

if ([selecedCellsArray containsObject:[NSString stringWithFormat:@"%@",rowNsNum]]  )
{

    if (![cell.progressLabel.text isEqualToString:@""]&& ![cell.progressLabel.text isEqualToString:@"Success"] && ![cell.progressLabel.text isEqualToString:@"Creating"]){
        cell.progressLabel.hidden = NO;
        cell.progressLine.hidden = NO;
    } else {
        cell.progressLabel.hidden = YES;
        cell.progressLine.hidden = YES;
      }
}
else{
    if(!oneItem.isProcessing && !cell.selected){
    cell.progressLabel.hidden = YES;
    cell.progressLine.hidden = YES;
    }
}
} else { //if processing
if (![processingCellsArray containsObject:[NSString stringWithFormat:@"%@",rowNsNum]]){
    [processingCellsArray addObject:[NSString stringWithFormat:@"%@",rowNsNum]];
    if (!cell.isSelected){

        [cell setSelected:YES];

    }
    cell.progressLabel.hidden = NO;
    cell.progressLine.hidden = NO;

    NSArray * arrayOfThingsIWantToPassAlong =
    [NSArray arrayWithObjects: cell, oneItem, indexPath, nil];

    if(!isMaking){
        [self performSelector:@selector(getProgress:)
                   withObject:arrayOfThingsIWantToPassAlong
                   afterDelay:0];
    } else{
    [self performSelector:@selector(getProgress:)
               withObject:arrayOfThingsIWantToPassAlong
               afterDelay:0.5];
    }

    isMaking = YES;

} else {
    if (!cell.isSelected){
        [cell setSelected:YES];
    }

    cell.progressLabel.hidden = NO;
    cell.progressLine.hidden = NO;

    NSArray * arrayOfThingsIWantToPassAlong =
    [NSArray arrayWithObjects: cell, oneItem, indexPath, nil];

    if(!isMaking){
        [self performSelector:@selector(getProgress:)
                   withObject:arrayOfThingsIWantToPassAlong
                   afterDelay:0];
    } else{
    [self performSelector:@selector(getProgress:)
               withObject:arrayOfThingsIWantToPassAlong
               afterDelay:0.3];
    }


    isMaking = YES;
    }

   }
    return cell;
 }

getProgress方法:

-(void)getProgress:(NSArray*)args{

if (progManager == nil && !progStop){
    __block AVMFilmsStore * oneItem = args[1];
    if(!oneItem.isLocal){
        __block AVMMovieCell * cell = args[0];
        __block NSIndexPath *indexPath = args[2];
        progManager = [AFHTTPRequestOperationManager manager];
        __block NSString *token = [defaults objectForKey:@"token"];
        __block NSString *header = [NSString stringWithFormat:@"Bearer %@",token];
        __block NSDictionary *params = @{@"lang": NSLocalizedString(@"lang",nil),@"project":oneItem.fileId};
        __block NSString *oneHundredPercent;
        __block NSString *progIsText;

        progManager.responseSerializer = [AFJSONResponseSerializer serializer];
        [progManager.requestSerializer setValue:header forHTTPHeaderField:@"Authorization"];
        if(cell.selected || isMaking) { //if I just check for "cell.selected" is always "NO"
            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
            [progManager POST:@"http://example.com/api/project/get-progress" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
                if ([[responseObject objectForKey:@"result"]isEqualToString:@"success"]){
                    progCreate = [responseObject objectForKey:@"progress"];

                    oneHundredPercent = @"100";
                    if ([progCreate intValue]==[oneHundredPercent intValue]){
                        if([processingCellsArray containsObject:[NSString stringWithFormat:@"%ld",(long)indexPath.row]]){
                            [processingCellsArray removeObject:[NSString stringWithFormat:@"%ld",(long)indexPath.row]];
                            [cell setSelected:NO];

                        }
                        [readyArray removeAllObjects];
                        [defaults setObject:@"false" forKey:@"isSomethingInSort"];
                        isMaking = NO;
                        [self getReadyMovies:progIsText nameLabel:oneItem.fileName];

                    } else{
                        if([progCreate intValue]>=50){
                            if([progCreate intValue]>=60){
                                self.navigationController.navigationItem.leftBarButtonItem.enabled = YES;
                               createMainButton.enabled = YES;
                            }
                            [[NSNotificationCenter defaultCenter] postNotificationName:@"gotFiftyNote" object:@"50"];
                            [cell.progressLine setProgress:[progCreate floatValue]/100 animated:YES];
                        } else {
                            [cell.progressLine setProgress:progUploadLimit];
                        }
                        progManager = nil;
                        progManager.responseSerializer = nil;
                        progManager.requestSerializer = nil;
                        token = nil;
                        header = nil;
                        params = nil;
                        progIsText = nil;
                        oneItem = nil;
                        cell = nil;
                        indexPath = nil;
                        isMaking = YES;
                        progCreate = nil;
                        oneHundredPercent = nil;

                        [self getProgress:args];
                    }
                }
            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
                NSLog(@"Error: %@", error.localizedDescription);
            }];

        }

    }
  }
}

任何建议都会对我有所帮助。我为这个问题头疼了两周。

【问题讨论】:

  • 您需要重构此代码并接受面向对象。使单元负责更新自身。 performSelector 几乎总是一种代码气味。您还会遇到问题,因为您正在从后台处理程序更新 UI,以及对 NSMutableArray 进行非线程安全更新的潜在问题
  • 几天前我遇到了同样的问题。检查 Rob 的评论和 Aaron 的示例。可能对你有帮助:link

标签: ios objective-c iphone uitableview


【解决方案1】:

我看到了您的代码,但使用这些大型方法有点难以理解。我不会跟踪数组中的处理单元。每个单元格都有一个对象来表示,这些对象有一个准备好的布尔值和一个进度值,对吧?所以尝试这样的事情:

  • 确保每个单元格都有一个 progressView 作为子视图。
  • 您的单元格类应该有一个名为 styleForReady:(bool)isReady andProgress:(nsinteger)progress 的公共方法
  • 为每个型号拨打服务电话以查看它们是否已完成。每当该服务调用返回时,您只需更新数组中的模型对象,并在它们获得新的进度值后执行 [self.tableView reloadData]。这将触发 numberOfRows(它应该返回 arrayOfObjects.count)和 cellForRowAtIndexPath:(它应该为那个 indexPath 出列单元格,获取代表那个单元格的模型,比如 arrayOfObjects[indexPath.row],最后,调用单元格来设置自己的样式基于该模型执行 [cell styleForReady:objectModel.ready andProgress:objectModel.progress])

请记住,控制器应该只跟踪模型对象,将单元格出列并告诉单元格设置样式传递模型。不要把所有的逻辑都放在控制器里。

【讨论】:

  • 感谢您的回复!一时不明白:我现在应该在哪里获得每个对象的进度?在“objectModel”类或单元类中?你的意思是我必须将我的getProgress 方法实现到UITableViewCell 的子类中?
  • 控制器负责模型。每个模型(NSObject 的子类,应该有进度并准备好作为属性)。该单元负责绘制,您的单元中应该有一个 styleWithProgress: 和Ready: 方法,该方法将负责根据模型中的新进度和就绪值更新progressView。当进度调用返回时,您更新模型(不是单元格),然后调用 reloadData,这将触发根据新更新的模型绘制 tableViewCells 所需的所有 UI 方法。
  • 好的,我在我的模型类(NSObject 的子类)中实现了方法getProgress,并且在每次调用此方法时,我更改了此类“readyProgress”属性的值,还实现了方法-(void)styleForReady:(BOOL)isReady andProgress:(float)progress(我需要它的浮点值.. 没关系。现在在我的cellForRowAtIndexPath 中检查未准备好的对象然后调用[cell styleForReady:NO andProgress:[oneItem getProgress]]; 但我不明白我应该在哪里调用[self.tableView reloadData]; 这就是为什么我只能在滚动时看到更改
  • 你不应该把状态放在单元格中。状态应保存在数据源中。
  • @vendettacore 每次您想要更新任何单元格时,即每当您的模型有新值时,您都必须执行 [self.tableView reloadData]。我会把它放在 viewWillAppear 中,每当你从服务器收到新数据时。 reloadData 调用 cellforRow 和 numberOfRows 方法,因此它将刷新所有可见单元格以及滚动时出现的单元格。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
  • 2020-10-20
相关资源
最近更新 更多