6

これはかなり複雑な質問だと思います。多数のダウンロード可能なコンテンツを表示する TableView があります。セル内のボタンをクリックすると、ダウンロードが開始されます。

しかし、私はいくつかの問題を抱えています: 1.progressBar が常に表示されるようにするにはどうすればよいですか?一度に2ファイル。いくつかのインスタンス変数を使用しているため、問題が発生するのではないかと心配しています。ある意味では、ミュージックアプリでiCloudからダウンロードするのと少し似ているはずです

これが私のコードです

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];   
    }
    //cell.tag = indexPath.row*10;
    Uebungsblaetter *uebungCell = [uebungsblattArray objectAtIndex:indexPath.row];
    cell.tag = indexPath.row*10;
    cell.textLabel.text = [self getFileNameOutOf:uebungCell.url];
    cell.textLabel.textColor = [UIColor grayColor];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    UIButton *dl = [UIButton buttonWithType:UIButtonTypeCustom];
    dl.tag = indexPath.row*10;
    [dl setBackgroundImage:[UIImage imageNamed:@"downloadButton.png"] forState:UIControlStateNormal];
    [dl setBackgroundImage:[UIImage imageNamed:@"downloadButtonH.png"] forState:UIControlStateHighlighted];
    [dl setFrame:CGRectMake(230.0, (cell.frame.size.height-28)/2, 28, 28)];
    [dl addTarget:self action:@selector(downloadFileWhenPressedButton:) forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:dl];
    UIProgressView *dlProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
    dlProgress.frame = CGRectMake(cell.frame.size.width-150, 17, 50, 9);
    dlProgress.tag =indexPath.row*10+1;
    dlProgress.progress = 0.0;
    [cell.contentView addSubview:dlProgress];
    [dlProgress setHidden:YES];   

    return cell;
}

//download methods
- (void)downloadFileWhenPressedButton:(UIButton*)sender{
    sender.hidden = YES;
    dlIndex = sender.tag/10;
    Uebungsblaetter *selectedUB = [uebungsblattArray objectAtIndex:dlIndex];
    NSURL *theUrl = [NSURL URLWithString:selectedUB.url];
    NSURLRequest *req=[NSURLRequest requestWithURL:theUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:120];
    dlCell = (UITableViewCell *)[[sender superview]superview];
    currDlProgress = (UIProgressView* )[dlCell.contentView viewWithTag:dlIndex*10+1];
    currDlProgress.hidden = NO;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    dlFilePath = [NSString stringWithFormat:@"%@/%@_%@", [paths objectAtIndex:0],self.courseLable.text,[self getFileNameOutOf:selectedUB.url]];
    NSURLConnection *con=[[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
    if (con) {
        myWebData = [NSMutableData data];
    }

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    UIApplication* app = [UIApplication sharedApplication];
    app.networkActivityIndicatorVisible = YES;
    currDlProgress.progress = 0;
    _totalFileSize = response.expectedContentLength;
    NSLog(@"%@",@"connection established");
    [myWebData setLength: 0];



}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    _receivedDataBytes += [data length];
    currDlProgress.progress = _receivedDataBytes / (float)_totalFileSize;

    NSLog(@"%@",@"connection receiving data");
    [myWebData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%@",@"connection failed");
    //  [AlertViewHandler showAlertWithErrorMessage:@"Sorry, there is no network connection. Please check your network and try again."];
    //  [self parserDidEndDocument:nil];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    UIApplication* app = [UIApplication sharedApplication];
    app.networkActivityIndicatorVisible = NO;
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.35];
    [currDlProgress setAlpha:0];
    [UIView commitAnimations];
    [myWebData writeToFile:dlFilePath atomically:YES];
    Uebungsblaetter *loadedUB = [uebungsblattArray objectAtIndex:dlIndex];
    loadedUB.downloaded = [NSNumber numberWithBool:YES];
    [courseTable reloadData];
}

誰かが手がかりや素敵なコード例を持っていればいいでしょう

4

2 に答える 2

22

プログレス バーが常に表示されるわけではないことを認識することが重要です (つまり、ユーザーはテーブルをスクロールでき、画面外になると同じセルを別のコンテンツの別のインデックス位置で再利用できます)。そのため、テーブル内のインデックス位置、合計ファイル サイズ、これまでにダウンロードされたバイト数など、アクティブなダウンロードに関するデータを保存できる場所を用意する必要があります。次に、セルが描画されるたびに、そのセルのアイテムが現在ダウンロードされているかどうかを確認し、ダウンロードされている場合は、適切なパーセンテージの進行状況でバーを表示する必要があります。

これを行う最も簡単な方法は、View Controller にプロパティを追加してこの情報を保存することです。NSMutablerrayオブジェクトのコレクションを保持する にすることができNSMutableDictionaryます。各ディクショナリには、アクティブなダウンロードに関する必要な情報が含まれます。

@property (nonatomic, strong) NSMutableArray *activeConnections;

まず、配列を次のように初期化しますviewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //...

    self.activeConnections = [[NSMutableArray alloc] init];
}

ボタンが押されるたびに、必要な情報を含む NSMutableDictionary オブジェクトを配列に追加します。

- (void)downloadFileWhenPressedButton:(UIButton*)sender
{
    // ...

    //  then create dictionary
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    [dict setObject:con forKey:@"connection"];  // save connection so we can reference later
    [dict setObject:[NSNumber numberWithInt:[sender.tag]/10] forKey:@"row"];  // this is the row index from your table
    [dict setObject:[NSNumber numberWithInt:999] forKey:@"totalFileSize"];  // dummy size, we will update when we know more
    [dict setObject:[NSNumber numberWithInt:0] forKey:@"receivedBytes"];

    [self.activeConnections addObject:dict];
}

また、2 つのユーティリティ メソッドを作成して、接続オブジェクト自体またはテーブル内の行インデックス位置のいずれかを使用して、配列から接続情報を簡単に取得できるようにします。

- (NSDictionary*)getConnectionInfo:(NSURLConnection*)connection
{
    for (NSDictionary *dict in self.activeConnections) {
        if ([dict objectForKey:@"connection"] == connection) {
            return dict;
        }
    }
    return nil;
}

- (NSDictionary*)getConnectionInfoForRow:(int)row
{
    for (NSDictionary *dict in self.activeConnections) {
        if ([[dict objectForKey:@"row"] intValue] == row) {
            return dict;
        }
    }
    return nil;
}

接続が確立されたら、予想される長さで辞書を更新します 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    [dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"totalFileSize"];
}

データを受信すると、受信したバイト数を更新し、プログレス バーを含むセルを再描画するように tableView に指示します。

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    NSNumber bytes = [data length] + [[dict objectForKey:@"receivedBytes"] intValue];

    [dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"receivedBytes"];

    int row = [[dict objectForKey:@"row"] intValue];
    NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                          withRowAnimation:UITableViewRowAnimationNone];
}

接続のダウンロードが完了したら、activeConnections 配列から接続を削除し、テーブル セルを再読み込みする必要があります。

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    [self.activeConnections removeObject:dict];

    int row = [[dict objectForKey:@"row"] intValue];
    NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                          withRowAnimation:UITableViewRowAnimationNone];
}

最後に、cellForRowAtIndexPath:activeConnections 配列の情報に基づいて、セルの進行状況バーを描画する必要があります。

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

    // remove any previous buttons or progress bars from this cell
    for (UIView *view in [cell.contentView subViews]) {

        if ([view isKindOfClass:[UIProgressView class]] || [view isKindOfClass:[UIButton class]]) {
            [view removeFromSuperView];
        }
    }

    // look for active connecton for this cell
    NSDictionary *dict = [self getConnectionInfoForRow:indexPath.row];

    if (dict) {
        // there is an active download for this cell, show a progress bar

        UIProgressView *dlProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
        dlProgress.frame = CGRectMake(cell.frame.size.width-150, 17, 50, 9);
        dlProgress.tag = indexPath.row*10+1;
        dlProgress.progress = [[dict objectForKey:@"receivedBytes"] intValue] / [[dict objectForKey:@"totalFileSize"] intValue];

        [cell.contentView addSubview:dlProgress];

    } else {
        // no active download, show the download button

        UIButton *dl = [UIButton buttonWithType:UIButtonTypeCustom];
        dl.tag = indexPath.row*10;
        [dl setBackgroundImage:[UIImage imageNamed:@"downloadButton.png"] forState:UIControlStateNormal];
        [dl setBackgroundImage:[UIImage imageNamed:@"downloadButtonH.png"] forState:UIControlStateHighlighted];
        [dl setFrame:CGRectMake(230.0, (cell.frame.size.height-28)/2, 28, 28)];
        [dl addTarget:self action:@selector(downloadFileWhenPressedButton:) forControlEvents:UIControlEventTouchUpInside];
        [cell.contentView addSubview:dl];
    }
}
于 2012-08-31T05:17:42.603 に答える
3

問題は、データとUIを混同していることです。問題の原因となる現在のダウンロードステータスを保存するために、各テーブルビューセルに依存しています。代わりに、セルに必要なデータ(つまり、ダウンロード中かどうか、現在のダウンロードの進行状況、ダウンロードされたデータなどを示すブール値)を格納できるカスタムオブジェクトを作成する必要があります。objectAtIndex:0次に、テーブルの最初のセルのデータなど、これらのオブジェクトの可変配列が必要です。

ダウンロードが開始されたら、アレイ内の関連するオブジェクトを更新します。理想的には、テーブルビューセルを作成するときは、NSKeyValueObservingプロトコルを使用して、基になるデータが変更されたときに自動的に通知され、データを適切に更新できるようにする必要があります。セルを再利用すると、そのデータを格納するオブジェクトが引き続き存在するため問題ありません。また、画面に戻ろうとしているためにセルを再作成する必要がある場合は、そのデータを使用して適切に表示できます。

これについてさらに説明が必要な場合はお知らせください。

于 2012-08-31T00:47:46.627 に答える