Saya telah menulis dua cara untuk memuat gambar di dalam sel UITableView saya. Dalam kedua kasus gambar akan memuat dengan baik tetapi ketika saya akan menggulir tabel gambar akan berubah beberapa kali sampai gulir akan berakhir dan gambar akan kembali ke gambar yang tepat. Saya tidak tahu mengapa ini terjadi.
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString:
@"http://myurl.com/getMovies.php"]];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
-(void)fetchedData:(NSData *)data
{
NSError* error;
myJson = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
[_myTableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// Return the number of rows in the section.
// Usually the number of items in your array (the one that holds your list)
NSLog(@"myJson count: %d",[myJson count]);
return [myJson count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.poster.image = [UIImage imageWithData:imgData];
});
});
return cell;
}
... ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
cell.poster.image = [UIImage imageWithData:data];
// do whatever you want with image
}
}];
return cell;
}
poster
? Mungkin itu adalah tampilan gambar di sel khususnya, jadi apa yang dilakukan EXEC_BAD_ACCESS benar. Anda benar bahwa Anda tidak boleh menggunakan sel sebagai repositori untuk data model, tapi saya tidak berpikir itu yang dia lakukan. Dia hanya memberi sel kustom apa yang dibutuhkan untuk menampilkan dirinya sendiri. Selanjutnya, dan ini adalah masalah yang lebih halus, saya akan berhati-hati tentang menyimpan gambar, itu sendiri, dalam model array Anda mendukung tampilan tabel Anda. Lebih baik menggunakan mekanisme caching gambar dan objek model Anda harus mengambil dari cache itu.Jawaban:
Dengan asumsi Anda sedang mencari perbaikan taktis cepat, apa yang perlu Anda lakukan adalah memastikan gambar sel diinisialisasi dan juga bahwa baris sel masih terlihat, misalnya:
Kode di atas mengatasi beberapa masalah yang berasal dari fakta bahwa sel digunakan kembali:
Anda tidak menginisialisasi gambar sel sebelum memulai permintaan latar belakang (artinya gambar terakhir untuk sel yang dikosongkan masih akan terlihat saat gambar baru sedang diunduh). Pastikan untuk
nil
melihatimage
properti gambar atau Anda akan melihat kerlipan gambar.Masalah yang lebih halus adalah bahwa pada jaringan yang sangat lambat, permintaan asinkron Anda mungkin tidak selesai sebelum sel bergulir dari layar. Anda dapat menggunakan
UITableView
metode inicellForRowAtIndexPath:
(jangan bingung denganUITableViewDataSource
metode yang disebut samatableView:cellForRowAtIndexPath:
) untuk melihat apakah sel untuk baris itu masih terlihat. Metode ini akan kembalinil
jika sel tidak terlihat.Masalahnya adalah bahwa sel telah digulirkan pada saat metode async Anda telah selesai, dan, lebih buruk lagi, sel telah digunakan kembali untuk baris lain dari tabel. Dengan memeriksa untuk melihat apakah baris masih terlihat, Anda akan memastikan bahwa Anda tidak secara tidak sengaja memperbarui gambar dengan gambar untuk baris yang sejak saat itu bergulir dari layar.
Agak tidak terkait dengan pertanyaan yang ada, saya masih merasa terdorong untuk memperbarui ini untuk meningkatkan konvensi dan API modern, terutama:
Gunakan
NSURLSession
daripada mengirim-[NSData contentsOfURL:]
ke antrian latar belakang;Gunakan
dequeueReusableCellWithIdentifier:forIndexPath:
daripadadequeueReusableCellWithIdentifier:
(tetapi pastikan untuk menggunakan prototipe sel atau kelas register atau NIB untuk pengidentifikasi itu); danSaya menggunakan nama kelas yang sesuai dengan konvensi penamaan Kakao (yaitu mulai dengan huruf besar).
Bahkan dengan koreksi ini, ada masalah:
Kode di atas bukanlah caching gambar yang diunduh. Itu berarti bahwa jika Anda menggulir gambar dari layar dan kembali ke layar, aplikasi mungkin mencoba untuk mengambil gambar lagi. Mungkin Anda akan cukup beruntung bahwa header respons server Anda akan mengizinkan caching yang cukup transparan yang ditawarkan oleh
NSURLSession
danNSURLCache
, tetapi jika tidak, Anda akan membuat permintaan server yang tidak perlu dan menawarkan UX yang jauh lebih lambat.Kami tidak membatalkan permintaan sel yang menggulir layar. Jadi, jika Anda dengan cepat menggulir ke baris ke-100, gambar untuk baris itu bisa ditumpuk di belakang permintaan 99 baris sebelumnya yang bahkan tidak terlihat lagi. Anda selalu ingin memastikan Anda memprioritaskan permintaan sel yang terlihat untuk UX terbaik.
Perbaikan paling sederhana yang mengatasi masalah ini adalah dengan menggunakan
UIImageView
kategori, seperti yang disediakan dengan SDWebImage atau AFNetworking . Jika mau, Anda dapat menulis kode sendiri untuk mengatasi masalah di atas, tetapi ini banyak pekerjaan, danUIImageView
kategori di atas sudah melakukan ini untuk Anda.sumber
updateCell.poster.image = nil
tocell.poster.image = nil;
updateCell dipanggil sebelum diumumkan.AFNetworking
pasti cara untuk pergi. Saya tahu tentang itu tetapi malas menggunakannya. Saya hanya mengagumi cara cache bekerja dengan garis kode sederhana mereka.[imageView setImageWithURL:<#(NSURL *)#> placeholderImage:<#(UIImage *)#>];
cellForRowAtIndexPath
menghasilkan kerlip gambar ketika saya gulir dengan cepat" dan saya menjelaskan mengapa itu terjadi serta bagaimana cara memperbaikinya. Tetapi saya terus menjelaskan mengapa bahkan itu tidak cukup, menggambarkan beberapa masalah yang lebih dalam, dan berpendapat mengapa Anda akan lebih baik menggunakan salah satu perpustakaan itu untuk menangani hal ini dengan lebih anggun (memprioritaskan permintaan untuk sel yang terlihat, caching untuk menghindari jaringan yang berlebihan. permintaan, dll.). Saya tidak jelas apa lagi yang Anda harapkan dalam menanggapi pertanyaan "bagaimana cara menghentikan gambar yang berkedip di tampilan tabel saya"./ * Saya telah melakukannya dengan cara ini, dan juga mengujinya * /
Langkah 1 = Daftarkan kelas sel khusus (dalam kasus sel prototipe dalam tabel) atau nib (dalam kasus nib khusus untuk sel khusus) untuk tabel seperti ini dalam metode viewDidLoad:
ATAU
Langkah 2 = Gunakan metode "dequeueReusableCellWithIdentifier UITableView: forIndexPath:" seperti ini (untuk ini, Anda harus mendaftar kelas atau nib):
sumber
Ada beberapa kerangka kerja yang mengatasi masalah ini. Hanya untuk beberapa nama:
Cepat:
Tujuan-C:
sumber
SDWebImage
tidak menyelesaikan masalah ini. Anda dapat mengontrol kapan gambar diunduh, tetapiSDWebImage
menetapkan gambarUIImageView
tanpa meminta Anda tentang izin untuk melakukan ini. Pada dasarnya, masalah dari pertanyaan tersebut masih belum diselesaikan dengan perpustakaan ini.Cepat 3
Saya menulis implementasi cahaya saya sendiri untuk pemuat gambar dengan menggunakan NSCache. Tidak ada gambar sel yang berkedip!
ImageCacheLoader.swift
Contoh penggunaan
sumber
Ini adalah versi cepat (dengan menggunakan kode obyektif C borad @Nitesh): -
sumber
Jawaban terbaik bukan cara yang benar untuk melakukan ini :(. Anda benar-benar terikat indexPath dengan model, yang tidak selalu baik. Bayangkan bahwa beberapa baris telah ditambahkan selama memuat gambar. Sekarang sel untuk indexPath yang diberikan ada di layar, tetapi gambar tidak lagi benar! Situasinya agak tidak mungkin dan sulit untuk ditiru tetapi itu mungkin.
Lebih baik menggunakan pendekatan MVVM, mengikat sel dengan viewModel di controller dan memuat gambar di viewModel (menetapkan sinyal ReactiveCocoa dengan metode switchToLatest), kemudian berlangganan sinyal ini dan tetapkan gambar ke sel! ;)
Anda harus ingat untuk tidak menyalahgunakan MVVM. Tampilan harus mati sederhana! Sedangkan ViewModels harus dapat digunakan kembali! Itu sebabnya sangat penting untuk mengikat View (UITableViewCell) dan ViewModel di controller.
sumber
UIImageView
solusi kategori yang saya sarankan, maka tidak ada masalah tentang jalur indeks.Dalam kasus saya, itu bukan karena caching gambar (SDWebImage Digunakan). Itu karena ketidakcocokan tag sel kustom dengan indexPath.row.
Di cellForRowAtIndexPath:
1) Tetapkan nilai indeks ke sel khusus Anda. Misalnya,
2) Pada utas utama, sebelum menetapkan gambar, periksa apakah gambar itu milik sel yang sesuai dengan mencocokkannya dengan tag.
sumber
Terima kasih "Rob" .... Saya memiliki masalah yang sama dengan UICollectionView dan jawaban Anda membantu saya untuk menyelesaikan masalah saya. Ini kode saya:
sumber
mycell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
tidak pernah nol, jadi ini tidak berpengaruh.visibleCells
seperti itu, tapi saya menduga menggunakan[collectionView cellForItemAtIndexPath:indexPath]
lebih efisien (dan itulah sebabnya Anda melakukan panggilan itu di tempat pertama).updateCell
tidaknil
, tetapi Anda kemudian tidak menggunakannya. Anda harus menggunakannya tidak hanya untuk menentukan apakah sel tampilan kumpulan masih terlihat, tetapi Anda kemudian harus menggunakanupdateCell
di dalam blok ini, tidakcell
(yang mungkin tidak berlaku lagi). Dan jelas, jika itunil
, Anda tidak perlu melakukan apa-apa (karena sel ini tidak terlihat).sumber
Saya pikir Anda ingin mempercepat pemuatan sel Anda pada saat pemuatan gambar untuk sel di latar belakang. Untuk itu kami telah melakukan langkah-langkah berikut:
Memeriksa file yang ada di direktori dokumen atau tidak.
Jika tidak memuat gambar untuk pertama kalinya, dan menyimpannya ke direktori dokumen telepon kami. Jika Anda tidak ingin menyimpan gambar di telepon maka Anda dapat memuat gambar sel secara langsung di latar belakang.
Sekarang proses memuat:
Cukup sertakan:
#import "ManabImageOperations.h"
Kode seperti di bawah ini untuk sel:
ManabImageOperations.h:
ManabImageOperations.m:
Silakan periksa jawaban dan komentar jika ada masalah ....
sumber
Cukup ubah,
Ke
sumber
Anda bisa meneruskan URL Anda,
sumber
sumber