{"id":3818,"date":"2010-08-31T12:06:19","date_gmt":"2010-08-31T10:06:19","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=3818"},"modified":"2010-08-31T12:06:19","modified_gmt":"2010-08-31T10:06:19","slug":"t068-progress-view-ed-esecuzione-di-task-in-background","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t068-progress-view-ed-esecuzione-di-task-in-background\/","title":{"rendered":"T#068 &#8211; Progress view ed esecuzione di task in background"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg\" alt=\"T068 - Progress view esecuzione di task in background iphone\" title=\"T068-Progress-view-esecuzione-di-task-in-background\" width=\"97\" height=\"186\" class=\"alignleft size-full wp-image-4298\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg 386w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background-156x300.jpg 156w\" sizes=\"auto, (max-width: 97px) 100vw, 97px\" \/><\/a> Ad essere sincero non credevo di trovar un momento per realizzare due tutorial durante questa estate, limitiamoci a dire che rompersi lo zigomo proprio nel bel mezzo di agosto significa avere un mucchio di tempo libero seduto su un letto d&#8217;ospedale. E quale miglior modo per passare il tempo se non scrivendo un paio di tutorial per voi?<\/p>\n<p>Bene in questo primo tutorial volevo parlare delle progress bar e come fare ad aggiornarle mostrando sullo schermo del nostro terminale quanto manca alla conclusione di alcuni task particolarmente dispendiosi in termini di tempo. Pu\u00f2 sembrare un lavoro da poco, ma al contrario di quello che inizialmente pu\u00f2 sembrare, presenta alcune insidie.<\/p>\n<p>Credo che tutti sapete come creare una view based application e di aggiungere una progress view tramite Interface Builder, ma visto che il tempo non mi manca, ne perder\u00f2 un po\u2019 per spiegarlo anche a quelli di voi che si sono appena avvicinati alla programmazione per iPhone e magari non hanno ancora acquisito dimestichezza con questo strumento.<!--more--><\/p>\n<p>Una volta creato tramite Xcode il nostro progetto per un\u2019applicazione iPhone view based chiamata, per esempio, ProgressBar (ok lo so di non avere molta fantasia nei nomi \ud83d\ude42 ) apriamo il nostro ProgressBarViewController.h e aggiungiamo un riferimento che ci permetter\u00e0 di accedere alla progress view. A questo scopo modifichiamo il file come segue andando quindi ad aggiungere un puntatore a quella che sar\u00e0 la nostra progress view:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface ProgressBarViewController : UIViewController {\r\n\tIBOutlet UIProgressView *progressBar;\r\n}\r\n\r\n@end\r\n<\/pre>\n<p>Fatto questo non dobbiamo far altro che aprire con Interface Builder il file ProgressBarViewController.xib, aggiungere una progress view prendendola dalla library, trascinarla nella posizione in cui vogliamo metterla e collegarla alla variabile che abbiamo appena creato nel modo che possiamo vedere in figura:<\/p>\n<p><center><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/pb1.png\" alt=\"Operazione da eseguire in Interface Builder\" width=\"547\" height=\"306\" \/><br \/>\n<\/center><\/p>\n<p>Ora possiamo passare al tutorial vero e proprio. Cominciamo col creare una funzione che simuler\u00e0 una massiccia elaborazione di dati. Ipotizziamo per esempio 100 task della durata di 0.1 secondi ciascuno. La nostra funzione apparir\u00e0 come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)heavyDataProcessing {\r\n  NSInteger numberOfTasks = 100;\r\n    for (NSInteger tasksDone = 0; tasksDone &lt;= numberOfTasks; tasksDone++) {\r\n      [NSThread sleepForTimeInterval:0.1];\r\n      NSNumber *progress = [[NSNumber alloc] initWithFloat:((float)tasksDone \/ (float)numberOfTasks)];\r\n      [progress release];\r\n    }\r\n}\r\n<\/pre>\n<p>Per ora ci limitiamo a memorizzare il valore di progresso che abbiamo raggiunto nell\u2019esecuzione dei vari task in un NSNumber perch\u00e9 prima di scrivere le istruzioni per eseguire il nostro heavyDataProcessing e di modificare la progress view abbiamo bisogno di un paio di nozioni che vado adesso a spiegare nella maniera pi\u00f9 semplice possibile.<\/p>\n<p>Nel thread principale viene eseguito il main run loop che si preoccupa di catturare gli eventi (i pi\u00f9 comuni sono i tocchi sullo schermo). Quello che interessa a noi per\u00f2 \u00e8 che anche la modifica al valore che la progress view deve visualizzare rappresenta un evento. Una volta che il main run loop riceve un evento questo lo passa all\u2019UIResponder pi\u00f9 opportuno (ovvero la nostra UIProgressView, che eredita da UIView che a sua volta eredita da UIResponder) che lo gestir\u00e0, nel nostro caso verr\u00e0 ridisegnando la progress view con il valore aggiornato. Ora se noi invochiamo il metodo heavyDataProcessing normalmente, questo verr\u00e0 eseguito nel main thread. Verr\u00e0 quindi bloccata l\u2019esecuzione del run loop per permettere l\u2019esecuzione del metodo. Questo fatto che a prima vista ci sembra una stupidata ha un effetto piuttosto micidiale. Niente run loop significa niente gestione degli eventi che nel nostro caso si traduce in nessun update del valore visualizzato dalla nostra progress bar (che verr\u00e0 aggiornata solo al termine della funzione). Per ovviare a questo problema ci basta ricorrere ad un piccolo espediente: eseguiamo la funzione per il data processing in un thread secondario chiamato background thread limitandoci ad eseguire nel main thread solo la semplice e di rapida esecuzione funzione per l\u2019update della progress bar.<br \/>\nVediamo ora come.<\/p>\n<p>Cominciamo invocando il metodo nel Background thread. Per far ci\u00f2 ridefiniamo il metodo viewDidLoad (in questo modo siamo anche sicuri che la progress view \u00e8 stata creata).<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)viewDidLoad {\r\n   [self performSelectorInBackground:@selector(heavyDataProcessing)\r\n                          withObject:nil];\r\n}\r\n<\/pre>\n<p>Ora la nostra funzione heavyDataProcessing verr\u00e0 eseguita in un thread separato. Per poter far funzionare il tutto correttamente, ci mancano ancora due passaggi:<\/p>\n<ol>\n<li>Scrivere la funzione che aggiorner\u00e0 la progress view (da eseguire nel main thread).<\/li>\n<li>Aggiungere la chiamata a questa funzione nella heavyDataProcessing.<\/li>\n<\/ol>\n<p>Cominciamo con scrivere la funzione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)updateProgressBar:(NSNumber *)progress {\r\n\tprogressBar.progress = [progress floatValue];\r\n}\r\n<\/pre>\n<p>Si tratta di una semplicissima funzione che prende come parametro il valore attuale di progresso della progress bar e glielo assegna.<\/p>\n<p>Andiamo ora a modificare la funzione heavyDataProcessing come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)heavyDataProcessing {\r\n   NSInteger numberOfTasks = 100;\r\n   for (NSInteger tasksDone = 0; tasksDone &lt;= numberOfTasks; tasksDone++) {\r\n      [NSThread sleepForTimeInterval:0.1];\r\n      NSNumber *progress = [[NSNumber alloc] initWithFloat:((float)tasksDone \/ (float)numberOfTasks)];\r\n      [self performSelectorOnMainThread:@selector(updateProgressBar:) withObject:progress waitUntilDone:NO];\r\n      [progress release];\r\n   }\r\n}\r\n<\/pre>\n<p>Come possiamo vedere ci siamo limitati ad a aggiungere la riga numero 6 che ci permette di far eseguire la funzione updateProgressBar nel main thread, passando come parametro  il nuovo valore da assegnare alla progress bar (valore che abbiamo calcolato e salvato nell\u2019NSNumber).<\/p>\n<p>Perfetto! Ora tutto dovrebbe funzionare a dovere. Premete su Build and Run e godetevi la progress bar che a poco a poco si riempie.<\/p>\n<p>Come tutte le altre volte, anche il codice di questo tutorial lo trovate hostato su <a title=\"Google Code\" href=\"http:\/\/code.google.com\/p\/devapptutorials\/downloads\/list\" target=\"_blank\">Google Code<\/a>.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg\" alt=\"T068 - Progress view esecuzione di task in background iphone\" title=\"T068-Progress-view-esecuzione-di-task-in-background\" width=\"386\" height=\"742\" class=\"aligncenter size-full wp-image-4298\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background.jpg 386w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/08\/T068-Progress-view-esecuzione-di-task-in-background-156x300.jpg 156w\" sizes=\"auto, (max-width: 386px) 100vw, 386px\" \/><\/a><br \/>\n<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ad essere sincero non credevo di trovar un momento per realizzare due tutorial durante questa estate, limitiamoci&#8230;<\/p>\n","protected":false},"author":181,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[46,24,6,247,5,4,88,377,378,17,120,1,48],"class_list":["post-3818","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-developer-iphone","tag-interface-builder","tag-iphone","tag-luca-di-franco","tag-objective-c","tag-programmazione","tag-programmazione-iphone","tag-progress-bar","tag-progress-view","tag-teoria","tag-tutorial","tag-tutorial-pratici","tag-uiprogressview"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3818","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\/181"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=3818"}],"version-history":[{"count":15,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3818\/revisions"}],"predecessor-version":[{"id":4301,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3818\/revisions\/4301"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=3818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=3818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=3818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}