{"id":4187,"date":"2010-07-30T10:28:31","date_gmt":"2010-07-30T08:28:31","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=4187"},"modified":"2010-08-03T20:57:43","modified_gmt":"2010-08-03T18:57:43","slug":"t067-caricare-immagini-nelle-tabelle-in-modalita-asincrona","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t067-caricare-immagini-nelle-tabelle-in-modalita-asincrona\/","title":{"rendered":"T#067 &#8211; Caricare immagini nelle tabelle in modalit\u00e0 asincrona"},"content":{"rendered":"<p>Salve a tutti, dopo una lunghissima pausa torno a scrivere qualche mini tutorial, spero abbiate seguito i miei articoli su piattaforma Bada nel frattempo! Oggi vorrei proporvi la risoluzione di un annoso problema riguardante il caricamento asyncrono di immagini all\u2019interno delle tabelle.<\/p>\n<p>Come sicuramente saprete, \u00e8 relativamente semplice in Xcode visualizzare un&#8217;immagine prendendo il link direttamente via HTTP, ma il caricamente delle righe delle table richiede che vengano scaricate le immagini che visualizziamo PRIMA di visualizzare la riga stessa. L\u2019obiettivo che volevo raggiungere era lo stesso che potete vedere sfogliando l\u2019applicazione \u2018App Store\u2019 nella sezione categoria su iPhone\/iPod\/iPad\u2026 in cui se ci fate caso, vedrete apparire immediatamente i testi e poco dopo le 5 icone che vengono scaricate in background asincronicamente (gran parola!).<!--more--><\/p>\n<p>Innanzitutto creaiamo la classe &#8220;AsyncImageView&#8221; che richiameremo dal nosto metodo &#8220;cellForRowAtIndexPath&#8221;.<\/p>\n<p>Di seguito il file AsyncImageView.h<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import <UIKit\/UIKit.h>\r\n\r\n@interface AsyncImageView : UIView {\r\n    \/\/could instead be a subclass of UIImageView instead of UIView, depending on what other features you want to \r\n    \/\/ to build into this class?\r\n    \r\n    NSURLConnection* connection; \/\/keep a reference to the connection so we can cancel download in dealloc\r\n    NSMutableData* data; \/\/keep reference to the data so we can collect it as it downloads\r\n    \/\/but where is the UIImage reference? We keep it in self.subviews - no need to re-code what we have in the parent class\r\n    \r\n}\r\n\r\n- (void)loadImageFromURL:(NSURL*)url;\r\n- (UIImage*) image;\r\n\r\n@end\r\n<\/pre>\n<p>Ed il relativo file di implementazione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import \"AsyncImageView.h\"\r\n \r\n \r\n@implementation AsyncImageView\r\n \r\n- (void)dealloc {\r\n\t[connection cancel]; \/\/in case the URL is still downloading\r\n\t[connection release];\r\n\t[data release]; \r\n    [super dealloc];\r\n}\r\n \r\n \r\n- (void)loadImageFromURL:(NSURL*)url {\r\n\tif (connection!=nil) { [connection release]; } \/\/in case we are downloading a 2nd image\r\n\tif (data!=nil) { [data release]; }\r\n \r\n\tNSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];\r\n\tconnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; \/\/notice how delegate set to self object\r\n}\r\n \r\n \r\n\/\/the URL connection calls this repeatedly as data arrives\r\n- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {\r\n\tif (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; } \r\n\t[data appendData:incrementalData];\r\n}\r\n \r\n\/\/the URL connection calls this once all the data has downloaded\r\n- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {\r\n\t\/\/so self data now has the complete image \r\n\t[connection release];\r\n\tconnection=nil;\r\n\tif ([[self subviews] count]&gt;0) {\r\n\t\t\/\/then this must be another image, the old one is still in subviews\r\n\t\t[[[self subviews] objectAtIndex:0] removeFromSuperview]; \/\/so remove it (releases it also)\r\n\t}\r\n \r\n\t\/\/make an image view for the image\r\n\tUIImageView* imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];\r\n\t\/\/make sizing choices based on your needs, experiment with these. maybe not all the calls below are needed.\r\n\timageView.contentMode = UIViewContentModeScaleAspectFit;\r\n\timageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );\r\n\t[self addSubview:imageView];\r\n\timageView.frame = self.bounds;\r\n\t[imageView setNeedsLayout];\r\n\t[self setNeedsLayout];\r\n \r\n\t[data release]; \/\/don't need this any more, its in the UIImageView now\r\n\tdata=nil;\r\n}\r\n \r\n- (UIImage*) image {\r\n\tUIImageView* iv = [[self subviews] objectAtIndex:0];\r\n\treturn [iv image];\r\n}\r\n \r\n@end\r\n<\/pre>\n<p>Una volta che abbiamo la classe pronta, baster\u00e0 copiarla dentro a qualsiasi progetto per poterla utilizzare, vediamo come.<\/p>\n<p>Vi riporto per completezza tutto il metodo &#8220;cellForRowAtIndexPath&#8221;, che come saprete si occupa di valorizzare la riga che stiamo caricando in quel momento.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (UITableViewCell *)tableView:(UITableView *)tableView\r\n\t\t cellForRowAtIndexPath:(NSIndexPath *)indexPath {\r\n \r\n    static NSString *CellIdentifier = @\"ImageCell\";\r\n    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];\r\n \r\n    if (cell == nil) {\r\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"CellaRiepilogo\"  owner:self options:NULL];\r\n\t\tcell = nibLoadedCell;\r\n \r\n    } else {\r\n\t\tAsyncImageView* oldImage = (AsyncImageView*)\r\n\t\t[cell.contentView viewWithTag:999];\r\n\t\t[oldImage removeFromSuperview];\r\n    }\r\n \r\n\tCGRect frame;\r\n\tframe.size.width=47; frame.size.height=47;\r\n\tframe.origin.x=8; frame.origin.y=8;\r\n\tAsyncImageView* asyncImage = [[[AsyncImageView alloc]\r\n\t\t\t\t\t\t\t\t   initWithFrame:frame] autorelease];\r\n\tUIImage *myImage = [UIImage imageNamed:@\"blackaccessorybutton.png\"];\r\n\tUIImageView *imageView = [[UIImageView alloc] initWithImage:myImage];\r\n\t[cell setAccessoryView:imageView];\r\n \r\n \r\n\tSciopero *sciopero = [dati objectAtIndex:indexPath.row];\r\n \r\n\tUILabel\t\t*dataLabel\t= (UILabel *)[cell viewWithTag:1];\r\n\tUILabel\t\t*settoreLabel= (UILabel *)[cell viewWithTag:2];\r\n\tUILabel\t\t*modalitaLabel= (UILabel *)[cell viewWithTag:3];\r\n\tUILabel\t\t*descrizioneLabel= (UILabel *)[cell viewWithTag:4];\r\n \r\n \r\n\tdataLabel.text = [NSString stringWithFormat:@\"%@\", [sciopero.data uppercaseString]];\r\n\tsettoreLabel.text = [NSString stringWithFormat:@\"%@\", sciopero.settore];\r\n\tmodalitaLabel.text = [NSString stringWithFormat:@\"%@\", [sciopero.modalita lowercaseString]];\r\n\tdescrizioneLabel.text = [NSString stringWithFormat:@\"%@\", [sciopero.descrizione lowercaseString]];\r\n \r\n \r\n\tasyncImage.tag = 999;\r\n\tNSURL *url = [NSURL URLWithString: sciopero.icona];\t\r\n\t\/\/UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];\r\n\t\/\/categoria.immagine  = img;\r\n \r\n\t[asyncImage loadImageFromURL:url];\r\n \r\n\t[cell.contentView addSubview:asyncImage];\r\n \r\n    return cell;\r\n}\r\n<\/pre>\n<p>Nel mio caso utilizzo una cella personalizzata con uno XIB associato di nome &#8220;CellaRiepilogo.xib&#8221;.<\/p>\n<p>La parte da personalizzare a seconda dei casi \u00e8 la seguente:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nCGRect frame;\r\n\tframe.size.width=47; frame.size.height=47;\r\n\tframe.origin.x=8; frame.origin.y=8;\r\n\tAsyncImageView* asyncImage = [[[AsyncImageView alloc]\r\n\t\t\t\t\tinitWithFrame:frame] autorelease];\r\n<\/pre>\n<p>Ossia, creiamo il frame delle dimensioni che ci interessano (nel mio caso 47\u00d747) e decidiamo dove farlo apparire (in questo caso coordinate x=8 e y=8).<\/p>\n<p>Successivamente:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nasyncImage.tag = 999;\r\n\tNSURL *url = [NSURL URLWithString: sciopero.icona];\t\r\n\t[asyncImage loadImageFromURL:url];\r\n\t[cell.contentView addSubview:asyncImage];\r\n<\/pre>\n<p>E il gioco \u00e9 fatto!<\/p>\n<p>Ricordatevi di mettere l&#8217;import:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import \"AsyncImageView.h\"\r\n<\/pre>\n<p>Non ho scritto io quella classe, e purtroppo non ricordo dove l&#8217;ho pescata, per\u00f3 ne ho trovate diverse , e questa l\u2019ho personalizzata in diverse parti.<\/p>\n<p>Questo stesso codice l\u2019ho usato gi\u00e1 in parecchie applicazioni:<\/p>\n<ul>\n<ol>iQuimall, mi serviva per caricare le cover\/skin degli iphone via web<\/ol>\n<ol>iScioperi Trasporti \u2013 dovevo caricare tutti i dati comprensive di immagini da un mio XML su web<br \/>\n(questo spezzone di codice viene proprio da l\u00ed!)<\/ol>\n<ol>Tutte le altre mie app, che hanno nel tab bar l\u2019opzione &#8220;Altre App&#8221; appare la lista completa delle<br \/>\napplicazioni da me realizzate, e cliccando sulla riga si va direttamente sull\u2019AppStore per l\u2019acquisto!<\/ol>\n<\/ul>\n<p>Spero vi sia utile!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oggi vorrei proporvi la risoluzione di un annoso problema riguardante il caricamento asyncrono di immagini all\u2019interno delle tabelle.<\/p>\n<p>Come sicuramente saprete, \u00e9 relativamente semplice in xcode visualizzare un\u2019immagine prendendo il link direttamente via HTTP, ma il caricamente delle righe delle table richiede che vengano scaricate le immagini che visualizziamo PRIMA di visualizzare la riga stessa.<\/p>\n","protected":false},"author":169,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[360,359,369,370,53,361],"class_list":["post-4187","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-asincrono","tag-async","tag-caricare-immagini-iphone","tag-download-asincrono-iphone","tag-immagini","tag-table"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/169"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=4187"}],"version-history":[{"count":7,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4187\/revisions"}],"predecessor-version":[{"id":4254,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4187\/revisions\/4254"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=4187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=4187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=4187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}