2

イメージを非同期にロードし、ロードされたら UITableViewCell に配置する UITableView があります (「LazyTableImages」チュートリアルとほぼ同じコードを使用しています)。これは、テーブルをスクロールするとすべての画像で正常に機能しますが、ビューの最初の画像は読み込まれません。

NSURLConnection リクエストを実際に送信するクラスが正しく呼び出されているため、コードは間違いなく正常に機能しています (NSLog を追加してコンソールに到達しました)。NSURLConnection はデリゲート メソッド (didReceiveData、connectionDidFinishLoading など) を呼び出していません。

これが私のコードです:


HomeController.m

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

 if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

  NSArray *feed = [feeds objectAtIndex: indexPath.row];

  /**
    * Name of person
   */
  [...]

  /**
    * Feed entry
   */
  [...]

  /**
    * Misc work
   */
  [...]

 }

 FeedRecord *feedRecord = [self.entries objectAtIndex:indexPath.row];

 if( !feedRecord.image ) {

  if (self.table.dragging == NO && self.table.decelerating == NO)
  {
   [self startIconDownload:feedRecord forIndexPath:indexPath];
  }

  cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];                

 }

    return cell;
 }

    - (void)startIconDownload:(FeedRecord *)feedRecord forIndexPath:(NSIndexPath *)indexPath
    {
        IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
        if (iconDownloader == nil) 
        {
            iconDownloader = [[IconDownloader alloc] init];
            iconDownloader.feedRecord = feedRecord;
            iconDownloader.indexPathInTableView = indexPath;
            iconDownloader.delegate = self;
            [imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
            [iconDownloader startDownload];
            [iconDownloader release];   
        }
    }

IconDownload.m

#import "IconDownloader.h"
#import "FeedRecord.h"

#define kAppIconHeight 48

@implementation IconDownloader

@synthesize feedRecord;
@synthesize indexPathInTableView;
@synthesize delegate;
@synthesize activeDownload;
@synthesize imageConnection;

#pragma mark

- (void)dealloc
{
    [feedRecord release];
    [indexPathInTableView release];

    [activeDownload release];

    [imageConnection cancel];
    [imageConnection release];

    [super dealloc];
}

- (void)startDownload
{
 NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log
    self.activeDownload = [NSMutableData data];
    // alloc+init and start an NSURLConnection; release on completion/failure
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
                             [NSURLRequest requestWithURL:
                              [NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
    self.imageConnection = conn;
 NSLog(@"%@",conn); // this shows in log
    [conn release];
}

- (void)cancelDownload
{
    [self.imageConnection cancel];
    self.imageConnection = nil;
    self.activeDownload = nil;
}


#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
 NSLog(@"%@ %@",@"Got data for", feedRecord.profilePicture);
    [self.activeDownload appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
 NSLog(@"%@",@"Fail!");
 // Clear the activeDownload property to allow later attempts
    self.activeDownload = nil;

    // Release the connection now that it's finished
    self.imageConnection = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  NSLog(@"%@ %@",@"Done", feedRecord.profilePicture);
   // Set appIcon and clear temporary data/image
    UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];

 self.feedRecord.image = image;

    self.activeDownload = nil;

 [image release];

    // Release the connection now that it's finished
    self.imageConnection = nil;

 NSLog(@"%@ %@",@"Our delegate is",delegate);
    // call our delegate and tell it that our icon is ready for display
    [delegate feedImageDidLoad:self.indexPathInTableView];
}

@end

他の誰かがこのようなことを経験したことがありますか、または私のコードの問題を特定できますか? ありがとう!

4

5 に答える 5

1

このコードを使用できます

[tableView performSelector:@selector(reloadData) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];

代わりは

[tableView reloadData];
于 2011-11-26T09:00:41.497 に答える
1

startDownload メソッドで作成した NSURLConnection オブジェクトの start メソッドを呼び出さないでください。

必ず実行してください:

- (void)startDownload
{
    NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log
    self.activeDownload = [NSMutableData data];
    // alloc+init and start an NSURLConnection; release on completion/failure
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
                            [NSURLRequest requestWithURL:
                            [NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
    self.imageConnection = conn;
    NSLog(@"%@",conn); // this shows in log
    [conn start];
    [conn release];
}

コンストラクターを使用することもできます: initWithRequest:delegate:startImmediately:

また、ユーザーがスクロールすると実行ループが実行されるため、ダウンロードがブロックされます。「コモンモード」で接続を登録するだけです:

[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

から抽出: how-to-avoid-blocked-downloads-during-scrolling

于 2012-01-28T07:48:26.190 に答える
0

あなたは私たちを始めませんNSURLConnection。で初期化するか、初期化後に-[NSURLConnection initWithRequest:delegate:startImmediately:]手動で呼び出し-[NSURLConnection start]ます。

于 2010-06-09T09:04:50.163 に答える
0

ここを見てください: http://www.depl0y.com/?p=345 たぶん役立つでしょう。

編集:はい、私のために働いています。があなたのために働いているのか、それとももっと情報が必要なのか教えてください.

于 2010-08-24T11:26:12.973 に答える
0

同じ問題があります。また、私はあなたとほぼ同じコードを使用しています (Apple サンプルの LazyTableImages からのものです)。

Apple のテスト プロジェクトのコードは機能しますが、私のプロジェクトでは機能しませんでした。ただし、Apple のコードのコピーを作成しただけです。

私が見つけたのは:

NSLog(@"Is%@ main thread", ([NSThread isMainThread] ? @"" : @" NOT"));

cellForRowAtIndexPath: と IconDownload.m の startDownload: (両方のプロジェクト) で、それが Apple のサンプルのメイン スレッドであることがわかりましたが、私のコードのメイン スレッドではありません。

これが問題かもしれません。

解決方法はありますか?


編集 !!!解決しました!

メインスレッドを強制的に使用しました

NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:entry.imageURL, @"imageURL", indexPath, @"indexPath", nil];
[self performSelectorOnMainThread:@selector(startIconDownload:) withObject:info waitUntilDone:NO];

in cellForRowAtIndexPath: メソッドに複数の引数を送信するには、辞書が必要です。

コードで同様のソリューションを実行できます。次の行を置き換えます。

[self startIconDownload:feedRecord forIndexPath:indexPath];

私のコードで startIconDownload: をこのように変更します

- (void)startIconDownload:(NSDictionary *)info
{
    NSString *url = [info objectForKey:@"imageURL"];
    NSIndexPath *indexPath = [info objectForKey:@"indexPath"];
    ...
}

一部の変数は、アプリで異なる場合があります。

しかし、メインスレッドを強制せずにAppleのサンプルでなぜそれが機能するのか理解できません。

何か案が?

于 2011-02-04T19:08:56.490 に答える