2012-09-07 31 views
15

Tôi hiện đang cố gắng tải danh sách UITableView của Flickr Photo (cs193p iOS Stanford, bài tập 5). Để tránh sự kiện chặn giao diện người dùng, tôi đã hoãn tải xuống hình thu nhỏ của từng ô thành một hàng đợi khác (nhưng hãy cập nhật giao diện người dùng trở lại trong hàng đợi chính). Mã này không tải không đồng bộ các hình ảnh, mặc dù không thêm hình thu nhỏ khi tôi nhấp vào hàng UITableViewCell. (xem ảnh chụp màn hình bên dưới). Bất kỳ ý tưởng những gì tôi đang làm sai?Không đồng bộ UITableViewCell Tải hình ảnh bằng cách sử dụng GCD

PS: Tôi đã xem xét một số câu hỏi về Stackoverflow khác & Ví dụ về LazyTableImages của Apple, nhưng tôi vẫn tin rằng đây là cách sạch nhất để đạt được kết quả mong muốn.

Cảm ơn!

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Photo List Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    // Configure the cell 
    NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row]; 


    if (photo != nil) { 
     if ([[photo objectForKey:@"title"] length] > 0) { 
      cell.textLabel.text = [photo objectForKey:@"title"]; 
     } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) { 
      cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"]; 
     } else { 
      cell.textLabel.text = @"Unknown"; 
     } 
    } 
    cell.imageView.image = [[UIImage alloc] initWithCIImage:nil]; 

    // Fetch using GCD 
    dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL); 
    dispatch_async(downloadThumbnailQueue, ^{ 
     UIImage *image = [self getTopPlacePhotoThumbnail:photo]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      if ([self.tableView.visibleCells containsObject:cell]) { 
       [cell.imageView setImage:image]; 
      } 
     }); 
    }); 
    dispatch_release(downloadThumbnailQueue); 

    return cell; 
} 

Trước khi nhấp chuột vào một hàng Before clicking a row

Sau khi chọn hàng After selecting the row

UPDATE: Đối với những người quan tâm, đây là mã cuối cùng tôi đã sử dụng:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Photo List Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    // Configure the cell 
    NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row]; 

    if (photo != nil) { 
    if ([[photo objectForKey:@"title"] length] > 0) { 
     cell.textLabel.text = [photo objectForKey:@"title"]; 
    } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) { 
     cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"]; 
    } else { 
     cell.textLabel.text = @"Unknown"; 
    } 
    } 
    cell.imageView.image = [[UIImage alloc] initWithCIImage:nil]; 

    // Fetch using GCD 
    dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL); 
    dispatch_async(downloadThumbnailQueue, ^{ 
    UIImage *image = [self getTopPlacePhotoThumbnail:photo]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     UITableViewCell *cellToUpdate = [self.tableView cellForRowAtIndexPath:indexPath]; // create a copy of the cell to avoid keeping a strong pointer to "cell" since that one may have been reused by the time the block is ready to update it. 
     if (cellToUpdate != nil) { 
      [cellToUpdate.imageView setImage:image]; 
      [cellToUpdate setNeedsLayout]; 
     } 
    }); 
    }); 
    dispatch_release(downloadThumbnailQueue); 

    return cell; 
} 
+0

Hey, đây hoàn toàn là chủ đề, nhưng tự hỏi nếu bên trong khối bạn gửi đến chủ đề chính, thay vì kiểm tra đối tượng bình đẳng trên 'ô', kiểm tra xem một ô tại' indexPath' có tồn tại không? –

+0

Tôi chỉ thử điều này: if ([self.tableView cellForRowAtIndexPath: indexPath]! = Nil) {... etc} và nó cũng hoạt động tốt. Đó là những gì bạn có trong tâm trí? – sybohy

+0

Phải và không sử dụng 'cell.imageView' trực tiếp trong khối của bạn mà là lấy ô ở' indexPath' và sử dụng chế độ xem hình ảnh của nó. Tôi nghĩ rằng bạn có thể gặp vấn đề với việc tái sử dụng ô nếu bạn sử dụng 'ô' trực tiếp theo cách nó được sắp xếp bên trong khối chuỗi chính của bạn. –

Trả lời

15

Bạn nên gọi setNeedsLayout trên ô sau khi đặt hình thu nhỏ.

Từ Doc Apple:.

"Gọi phương pháp này vào chủ đề chính của ứng dụng của bạn khi bạn muốn điều chỉnh cách bố trí của subviews của view Phương pháp này làm cho một lưu ý của các yêu cầu và trả về ngay lập tức Bởi vì phương pháp này không. không bắt buộc cập nhật ngay lập tức, nhưng thay vì chờ chu kỳ cập nhật tiếp theo, bạn có thể sử dụng nó để vô hiệu hóa bố cục của nhiều chế độ xem trước khi bất kỳ lượt xem nào được cập nhật. Hành vi này cho phép bạn hợp nhất tất cả các cập nhật bố cục của mình thành một chu kỳ cập nhật, thường tốt hơn cho hiệu suất. "

+0

wow.nó thật nhanh! Cảm ơn Carl, tôi sẽ không bao giờ tự mình tìm ra nó. Cảm ơn một lần nữa !! – sybohy

+0

Bạn được chào đón, vui vì nó đã hoạt động! –

+0

Thực ra, câu hỏi nhanh: về mặt kỹ thuật có tốt hơn không khi gọi [cell setNeedsLayout]? Tôi đã đọc tài liệu của Apple cho layoutSubviews và đây là những gì tôi tìm thấy: "Bạn không nên gọi phương thức này trực tiếp. Nếu bạn muốn ép buộc cập nhật bố cục, hãy gọi phương thức setNeedsLayout thay vì làm như vậy trước khi cập nhật bản vẽ tiếp theo . " Bạn nghĩ sao? (cả hai chức năng hoạt động bằng cách này) – sybohy

0

Một giải pháp khác (và giải pháp mà tôi đã sử dụng cho bài tập đó) là gọi setNeedsDisplay trên imageView của ô khi bạn đã gán UIImage cho imageView đó.

Vì vậy, về cơ bản, tôi đã tạo một lớp có tên là FlickrDownloader bao bọc chức năng của FlickrFetcher (cũng như mã bộ nhớ đệm của tôi). FlickrDownloader có phương pháp này:

(void)getImageForPhotoInfo:(NSDictionary *)photoInfo ofFormat:(FlickrPhotoFormat)format withCallback:(image_setter_callback_t)callback; 

này về cơ bản là một cuộc gọi đến các chức năng tương tự của FlickrFetcher, nhưng nó cho biết thêm một thats callback được gọi khi kết thúc tải bức ảnh. Trong trường hợp cập nhật imageView của UITableViewCell, hàm gọi lại trông giống như sau:

image_setter_callback_t setImage = ^(UIImage *image){ 
    cell.imageView.image = image; 
    [cell.imageView setNeedsDisplay]; 
}; 
+0

Đã nhận được xung quanh ô thiết lập khung thành '(0,0,0,0)'? Khi tôi thử một cái gì đó tương tự nó đã không thay đổi kích cỡ cho đến khi tôi buộc 'layoutSubviews' để được gọi. Bạn có đang sử dụng hình ảnh trình giữ chỗ không? –

+0

nếu bạn gọi [cell.imageView setNeedsDisplay], điều đó có yêu cầu lớp của bạn triển khai phương thức drawRect không? Kiểm tra lại vào mùa thu 2011 bài giảng 4 slide # 8, setNeedsDisplay thiết lập mọi thứ để gọi drawRect. Nó không thực sự nói rằng nó có nhiều hay ít hơn thế. Phải không? – sybohy

+0

@CarlVeazey Bạn đúng trong đó tôi đã sử dụng một hình ảnh giữ chỗ giống như ví dụ LazyTableImages. Vì đây là cách tiếp cận của tôi ngay từ đầu, có lẽ đó là cách tôi xoay quanh khung hình. –

Các vấn đề liên quan