7

画像をダウンロードするために作成しましたNSOperationQueue(Twitter for Cellから):

NSOperationQueue *queue = [[NSOperationQueue alloc]init];
   [queue addOperationWithBlock:^{
    NSString *ImagesUrl = [[NSString alloc]initWithFormat:@"http://api.twitter.com/1/users/profile_image/%@",[[status objectForKey:@"user"]objectForKey:@"screen_name"]];;
        NSURL *imageurl = [NSURL URLWithString:ImagesUrl];
        UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];
        [[NSOperationQueue mainQueue]addOperationWithBlock:^{
            if (img.size.width == 0 || [ImagesUrl isEqualToString:@"<null>"]) {
                [statusCell.imageCellTL setFrame:CGRectZero];
                statusCell.imageCellTL.image = [UIImage imageNamed:@"Placeholder"] ;
            }else

            [statusCell.imageCellTL setImage:img];

これは正常に機能しますが、スクロールを移動して表示すると、画像はまだ読み込まれており、画像が表示されるまで何度か変更されています。

そして、診断のProfile of Timeが好きではないので、これNSOperationQueueをBackgroundでなんとかしたかったのです。

ダウンロード済みの画像をダウンロードする必要のない「Imagecache」を作成する方法を示すこともできます。

**(Status = Twitter タイムラインの NSDictionary)。

編集::(すべてのセル)

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


    static NSString *CellIdentifier = @"Celulatime";
    UITableViewCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];


    if ( [Cell isKindOfClass:[TimeLineCell class]] ) {
        TimeLineCell *statusCell = (TimeLineCell *) Cell;
        status = [self.dataSource objectAtIndex:indexPath.row];


        statusCell.TextCellTL.text = [status objectForKey:@"text"];
        statusCell.NomeCellTL.text = [status valueForKeyPath:@"user.name"];
        statusCell.UserCellTL.text = [NSString stringWithFormat:@"@%@", [status valueForKeyPath:@"user.screen_name"]];


        NSDate *created_at = [status valueForKey:@"created_at"];
        if ( [created_at isKindOfClass:[NSDate class] ] ) {
            NSTimeInterval timeInterval = [created_at timeIntervalSinceNow];
            statusCell.timeCellTL.text = [self timeIntervalStringOf:timeInterval];
        } else if ( [created_at isKindOfClass:[NSString class]] ) {
            NSDate *date = [self.twitterDateFormatter dateFromString: (NSString *) created_at];
            NSTimeInterval timeInterval = [date timeIntervalSinceNow];
            statusCell.timeCellTL.text = [self timeIntervalStringOf:timeInterval];
        }

        NSString *imageUrlString = [[NSString alloc]initWithFormat:@"http://api.twitter.com/1/users/profile_image/%@",[[status objectForKey:@"user"]objectForKey:@"screen_name"]];;
        UIImage *imageFromCache = [self.imageCache objectForKey:imageUrlString];

        if (imageFromCache) {
            statusCell.imageCellTL.image = imageFromCache;
            [statusCell.imageCellTL setFrame:CGRectMake(9, 6, 40, 40)]; 
        }
        else
        {
            statusCell.imageCellTL.image = [UIImage imageNamed:@"TweHitLogo57"];
            [statusCell.imageCellTL setFrame:CGRectZero]; 

            [self.imageluckluck addOperationWithBlock:^{
                NSURL *imageurl = [NSURL URLWithString:imageUrlString];
                UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];

                if (img != nil) {


                    [self.imageCache setObject:img forKey:imageUrlString];

                    // now update UI in main queue
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

                        TimeLineCell *updateCell = (TimeLineCell *)[tableView cellForRowAtIndexPath:indexPath];

                        if (updateCell) {
                            [updateCell.imageCellTL setFrame:CGRectMake(9, 6, 40, 40)]; 
                            [updateCell.imageCellTL setImage:img];
                        }
                    }];
                }
            }];
        }


        }
    return Cell;
    }
4

3 に答える 3

12

いくつかの観察:

  1. 画像ごとに新しい を作成するのではなく、NSOperationQueueクラスで を定義してviewDidLoad(および ) で初期化し、そのキューに操作を追加する必要があります。また、多くのサーバーは、各クライアントからサポートする同時リクエストの数を制限しているため、それに応じて設定してください。NSCacheNSOperationQueuemaxConcurrentOperationCount

    @interface ViewController ()
    @property (nonatomic, strong) NSOperationQueue *imageOperationQueue;
    @property (nonatomic, strong) NSCache *imageCache;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
         [super viewDidLoad];
    
        self.imageOperationQueue = [[NSOperationQueue alloc]init];
        self.imageOperationQueue.maxConcurrentOperationCount = 4;
    
        self.imageCache = [[NSCache alloc] init];
    }
    
    // the rest of your implementation
    
    @end
    
  2. tableView:cellForRowAtIndexPath:(a) 非同期イメージの読み込みを開始する前に初期化する必要があります (そのため、再利用されたセルからの古いイメージは表示されませimageん)。(b) セルを更新する前に、セルがまだ表示されていることを確認します。

    NSString *imageUrlString = [[NSString alloc]initWithFormat:@"http://api.twitter.com/1/users/profile_image/%@",[[status objectForKey:@"user"]objectForKey:@"screen_name"]];;
    UIImage *imageFromCache = [self.imageCache objectForKey:imageUrlString];
    
    if (imageFromCache) {
        statusCell.imageCellTL.image = imageFromCache;
        [statusCell.imageCellTL setFrame: ...]; // set your frame accordingly
    }
    else
    {
        statusCell.imageCellTL.image = [UIImage imageNamed:@"Placeholder"];
        [statusCell.imageCellTL setFrame:CGRectZero]; // not sure if you need this line, but you had it in your original code snippet, so I include it here
    
        [self.imageOperationQueue addOperationWithBlock:^{
            NSURL *imageurl = [NSURL URLWithString:imageUrlString];
            UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageurl]];
    
            if (img != nil) {
    
                // update cache
                [self.imageCache setObject:img forKey:imageUrlString];
    
                // now update UI in main queue
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    // see if the cell is still visible ... it's possible the user has scrolled the cell so it's no longer visible, but the cell has been reused for another indexPath
                    TimeLineCell *updateCell = (TimeLineCell *)[tableView cellForRowAtIndexPath:indexPath];
    
                    // if so, update the image
                    if (updateCell) {
                        [updateCell.imageCellTL setFrame:...]; // I don't know what you want to set this to, but make sure to set it appropriately for your cell; usually I don't mess with the frame.
                        [updateCell.imageCellTL setImage:img];
                    }
                }];
            }
        }];
    }
    
  3. はこのメモリ警告に応答しませんが、メモリが少なくなるとオブジェクトを自動的に削除するため、特別な処理UIApplicationDidReceiveMemoryWarningNotificationは必要ありません。NSCache

上記のコードはまだテストしていませんが、理解していただければ幸いです。これが典型的なパターンです。元のコードには のチェックがありまし[ImagesUrl isEqualToString:@"<null>"]たが、これがどうなるかわかりませんが、 my 以外に追加のロジックが必要な場合はif (img != nil) ...、それに応じてその行を調整してください。

于 2013-01-21T18:02:25.463 に答える
1

Ray Wenderlich の良い例: http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues

ユーザーがキャンセルボタンを押した場合、操作をキャンセルするキャンセル機能も備えています。

于 2014-09-18T06:08:39.810 に答える