{"id":8984,"date":"2012-05-24T11:54:47","date_gmt":"2012-05-24T09:54:47","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=8984"},"modified":"2012-06-11T16:39:23","modified_gmt":"2012-06-11T14:39:23","slug":"guida-completa-all-uso-dei-block","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/guida-completa-all-uso-dei-block\/","title":{"rendered":"L#021 &#8211; Guida completa all&#8217;uso dei BLOCK"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/l015-objective-c-i-blocchi.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/l015-objective-c-i-blocchi.jpg\" alt=\"l015-objective-c-i-blocchi\" title=\"l015-objective-c-i-blocchi\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-6235\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/l015-objective-c-i-blocchi.jpg 200w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/l015-objective-c-i-blocchi-150x75.jpg 150w\" sizes=\"auto, (max-width: 200px) 100vw, 200px\" \/><\/a> Abbiamo gi\u00e0 parlato altre volte dei Block qui su devAPP, ad esempio in <a href=\"http:\/\/www.devapp.it\/wordpress\/l015-programmazione-block-based%E2%80%9D-i-blocchi-in-objective-c.html\" target=\"_blank\">questo articolo introduttivo<\/a> o ancora in <a href=\"http:\/\/www.devapp.it\/wordpress\/tips018-creare-animazioni-di-oggetti-tramite-metodi-block-based.html\" target=\"_blank\">quest&#8217;altro<\/a>, dove viene spiegato come usarli per creare delle animazioni sulle UIView.<br \/>\nVorrei tornarne a parlarne ancora una volta perch\u00e9 lo ritengo un argomento molto importante, che se conosciuto a fondo pu\u00f2 fornire un&#8217;utile strumento per risolvere diversi problemi di programmazione.<!--more--><\/p>\n<p>Prima di spiegare cosa sono i block e come usarli vorrei provare a fare un passo indietro per spiegare com&#8217;era il mondo prima dei block. Scopriremo che anche in questo caso gli ingegneri Apple sono stati in grado di prendere qualcosa di gi\u00e0 esistente e portalo ad un altro livello di astrazione rendendo il loro utilizzo davvero molto semplice.<\/p>\n<p>Tutti i linguaggi di programmazione permettono di dichiarare le funzioni (verr\u00f2 smentito nei commenti da chiss\u00e0 quale strano linguaggio&#8230;) ma in alcuni casi le funzioni costituiscono anche un vero e proprio tipo di dato, come un intero, una stringa e cos\u00ec via. In questo caso si dice che per quel linguaggio le funzioni sono &#8220;<strong>first-class object<\/strong>&#8221; (<a href=\"http:\/\/en.wikipedia.org\/wiki\/First-class_function\" target=\"_blank\">wikipedia<\/a>).<br \/>\nQuesta possibilit\u00e0 potremmo affermare che \u00e8 alla base della programmazione ad oggetti, perch\u00e9 come ho avuto modo di spiegare nel <a href=\"http:\/\/www.devapp.it\/wordpress\/category\/corso-completo-di-c\" target=\"_blank\">corso di C<\/a> una classe in fondo non \u00e8 altro che una struttura (nel senso di <strong>struct<\/strong>) con alcune variabili locali e alcune funzioni memorizzate all&#8217;interno della struttura. Se le funzioni non si potessero trattare come normali variabili sarebbe impensabile poterle inserire all&#8217;interno di una struttura.<br \/>\nMa a cosa pu\u00f2 servire poter trattare le funzioni come tipo di dato? A fare cose molto divertenti come ad esempio una funzione che prenda in input un elenco di valori e una seconda funzione e che restituisce l&#8217;elenco dei valori ai quali ha applicato singolarmente la seconda funzione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nfun map(list,f) {\r\n        for each l in list\r\n                f(l)\r\n        return list\r\n}\r\n<\/pre>\n<p>Oppure la funzione potrebbe prendere in input una lista pi\u00f9 una funzione e restiture true solo se almeno un oggetto della lista, passato alla funzione parametro, restituisce true:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nfun filter(list,f) {\r\n        for each l in list\r\n                if f(l) return true;\r\n}\r\n<\/pre>\n<p>Quindi avremmo un <em>applicatore<\/em> e un <em>filtratore<\/em> dinamici, il cui comportamento \u00e8 variabile e dipende dalla funzione usata come parametro, insomma: una versione ridotta e semplificata del delegate design pattern.<\/p>\n<p>Se volessimo realizzare, ad esempio, la funzione map in C, il codice che dovremmo utilizzare sarebbe questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\nint doSomeStuff(int a) {\r\n        return a * 42;\r\n}\r\nvoid map(int *list, int size, int (*f)(int)) {\r\n        int i = 0;\r\n        for (i = 0; i < size; ++i)\r\n        {\r\n                printf(\" %d \", f(list[i]));\r\n        }\r\n}\r\nint main(int argc, char **argv){\r\n        int (*f)(int); \/\/1\r\n        int lista[5] = {4,6,7,0,10};\r\n        f = doSomeStuff; \/\/2\r\n        map(lista,5,f);\r\n        return 0;\r\n}\r\n<\/pre>\n<p>Abbiamo la funzione da applicare (doSomeStuff) abbiamo la lista dei valori (list[5]) e come si pu\u00f2 vedere al punto \/\/1 ho dichiarato un puntatore ad una funzione che accetta come input un intero e che restituisce un intero.<br \/>\nAlla nota numero \/\/2 il puntatore \u00e8 stato assegnato alla funzione doSomeStuff, e finalmente richiamiamo la funzione map.<\/p>\n<p>Se non \u00e8 chiaro non preoccupatevi, uno dei motivi per cui a Cupertino hanno investito sulla creazione dei block \u00e8 proprio perch\u00e9 l'utilizzo a basso livello dei puntatori a funzione non \u00e8 proprio semplice.<\/p>\n<p>I linguaggi che implementano le funzioni come firt-class object sono veramente tanti, soprattutto linguaggi pi\u00f9 moderni come python oppure lua, spesso per\u00f2 in questi contesti si sente parlare di <strong>closure<\/strong>, (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Closure_(computer_science)\" target=\"_blank\">wikipedia<\/a>).<\/p>\n<p>Qual'\u00e8 la differenza?<\/p>\n<p>La differenza \u00e8 molto importante soprattutto perch\u00e9 i blocks sono un'implementazione di closure, non di semplici puntatori a funzione.<\/p>\n<p>La differenza \u00e8 che quando si parla di closure la funzione puntata pu\u00f2 accedere a tutte le variabili che erano presenti nel suo scope al momento della creazione, anche se l'oggetto che l'ha dichiarata non \u00e8 pi\u00f9 in memoria..... eh? Qui \u00e8 necessario fermarsi e riflettere...<\/p>\n<p>Supponiamo di avere il nostro programma scritto in python, o anche in obj-c. All'interno di una classe A dichiariamo una funzione che avr\u00e0 accesso ovviamente a tutte le variabili di istanza della classe A, poi creiamo un puntatore a questa funzione e lo passiamo in giro per il programma... a questo punto anche se la classe A dovesse essere deallocata, in ogni caso la funzione potrebbe accedere alle variabili di istanza perch\u00e9 ne ha una sua versione \"congelata\".  Un filo pi\u00f9 chiaro?<\/p>\n<p>Ecco quindi che se abbiamo capito questo \u00e8 molto pi\u00f9 semplice inquadrare i block nel loro reale contesto, sono una molto elegante implementazione delle clousure in obj-c.<\/p>\n<h4>Ma come si usano?<\/h4>\n<p>Per spiegare come utilizzare i block in obj-c non \u00e8 necessario creare un progetto iOS, possiamo usare un semplice programma a riga di comando, quindi apriamo Xcode e dal selettore del template scegliamo Application -> command line tool.<\/p>\n<p>Come si dichiara un block? Dipende ovviamente dal tipo di codice al quale dovr\u00e0 puntare, ad esempio questa sintassi:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint (^f)(int);\r\n<\/pre>\n<p>dichiara una variabile che si chiama f e che sar\u00e0 di tipo block. Il block in questione dovr\u00e0 ritornare un int e prendere in input un int;<\/p>\n<p>Un secondo esempio come questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nBOOL (^f2)(int);\r\n<\/pre>\n<p>La variabile si chiama f2, accetta un intero come parametro e restituisce un BOOL.<\/p>\n<p>Per l'inizializzazione si utilizza questa sintassi:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nf = ^(int num){\r\nreturn num * 2;\r\n};\r\n<\/pre>\n<p>In questo caso la varibabile f punta ad un blocco di codice che accetta un intero come parametro e che ne restituisce il valore moltiplicato per due.<\/p>\n<p>Va sottolineato che all'interno di questa porzione di codice possiamo accedere a tutte le variabili visibili, quindi se avessimo dichiarato una variabile fuori dal block, avremmo potuto utilizzarla anche all'interno, come in questo esempio:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint multiplier = 4;\r\nint (^f)(int);        \r\nf = ^(int num){\r\nreturn num * multiplier;\r\n};\r\n<\/pre>\n<p>Poich\u00e9, come abbiamo detto, si tratta di clousure e non di puntatori a funzioni, anche se dovessimo passare la variabile f ad un'altra classe non ci sarebbero problemi per l'accesso a multiplier, perch\u00e9 ciasun block porta con s\u00e9 una \"copia\" di tutte le variabili alle quali ha accesso.<\/p>\n<p>Per richiamare il block si fa semplicemente cos\u00ec:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSLog(@\"Risultato %d\",f(20));\r\n<\/pre>\n<p>Come si pu\u00f2 implementare quindi in obj-c la nostra funzione map? Il concetto \u00e8 del tutto simile a quanto abbiamo visto in C, cambia solo leggermente la sintassi:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n\/*\r\n * La funzione accetta la solita lista,\r\n * un intero che ne specifica la dimensione\r\n * e una variabile di tipo block.\r\n * Percorre la lista applicando il block all'elemento e stampando il valore\r\n *\/\r\nvoid map(int *lista, int size, int (^f)(int) ){\r\n    for (int i = 0; i < size; i++) {\r\n        NSLog(@\"%d\", f(lista[i]));\r\n    }\r\n}\r\n\r\nint main(int argc, const char * argv[])\r\n{\r\n    @autoreleasepool {\r\n        \/\/dichiarazione e inizializzazione della lista.\r\n        int lista[5] = {1,2,3,4,5};\r\n       \r\n        \/\/variabile esterna visibile anche dentro il block.\r\n        int multiplier = 4;\r\n       \r\n        \/\/variabile di tipo block\r\n        int (^f)(int);\r\n       \r\n        \/\/assegnazione della variabile block\r\n        f = ^(int num){\r\n            return num * multiplier;\r\n        };\r\n       \r\n        \/\/invocazione della funzione map\r\n        map(lista, 5, f);\r\n       \r\n    }\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Se siete arrivati fin qui adesso i block non dovrebbero avere pi\u00f9 segreti, proviamo infatti ad esaminare un metodo tra i tanti che li utilizzano, ad esempio guardiamo il prototipo di:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block\r\n<\/pre>\n<p>Questo metodo cosa ci dice?<\/p>\n<p>E' un metodo di istaza (il -) non restituisce alcun valore (void) e accetta un parametro di tipo block, che a sua volta non restituisce nulla e accetta tre parametri, un id, un intero e un puntatore a BOOL<\/p>\n<p>Se lo volessimo usare allora cosa dovremmo fare?<\/p>\n<ol>\n<li>Dichiarare una variabile di tipo block che accetti il giusto numero e tipo di parametri, in questo modo:\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">void (^p)(id, NSUInteger, BOOL *); \/\/la variabile in questo caso si chiama p<\/pre>\n<\/li>\n<li>Assegnare la variabile ad una porzione di codice corretta:\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\np = ^(id obj, NSUInteger index, BOOL *stop){\r\n            NSLog(@\"At index: %lu obj=%@\", index, obj);\r\n};\r\n<\/pre>\n<\/li>\n<li>Invocare il metodo enumerateObjectsUsingBlock su un nostro array passando il block come parametro:\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSArray *array = [NSArray arrayWithObjects:@\"ONE\",@\"TWO\", @\"THREE\", nil];\r\n[array enumerateObjectsUsingBlock:p];\r\n<\/pre>\n<\/li>\n<\/ol>\n<p>Questo \u00e8 ovviamente il modo pi\u00f9 prolisso, ma che fa capire bene cosa sta succedendo, probabilmente vi capiter\u00e0 pi\u00f9 spesso di saltare la dichiarazione e di mettere il block direttamente nell'invocazione, in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSArray *array = [NSArray arrayWithObjects:@\"ONE\",@\"TWO\", @\"THREE\", nil];\r\n[array enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){\r\nNSLog(@\"At index: %lu obj=%@\", index, obj);\r\n}];\r\n<\/pre>\n<p>Una domanda per i lettori: Perch\u00e9 l'ultimo parametro \u00e8 un puntatore a BOOL? Date la vostra risposta nei commenti!<\/p>\n<p>Prima di lasciarci un'ultima informazione molto utile quando si usano i block, abbiamo detto che tutte le variabili accessibili al block al momento della sua creazione (variabili globali, di istanza etc) sono \"copiate\" insieme al block in modo che anche se la sua esecuzione dovesse avvenire fuori dallo scope originale non ci sarebbero problemi di visibilit\u00e0... non abbiamo specificato per\u00f2 che queste variabili sono accessibili in sola lettura, perch\u00e9 gestirne anche la scrittura sarebbe un tantino oneroso per il sistema e poi non vogliamo realmente che del codice, in giro per il programma, possa modificare tutte le nostre variabili... non sarebbe molto pulito.<\/p>\n<p>Esiste un modo per\u00f2 per far s\u00ec che una variabile sia copiata in lettura e scrittura e consiste nell'utilizzare il modificatore di scope <strong>__block<\/strong> prima della dichiarazione, come in questo esempio:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n         __block int multiplier = 4; \/\/la variabile adesso \u00e8 modificabile anche dall'interno del block\r\nint (^f)(int);        \r\n        \/\/assegnazione della variabile block\r\n        f = ^(int num){\r\n            multiplier = multiplier + 1;\r\n            return num * multiplier;\r\n        };\r\n<\/pre>\n<p>Con questo credo proprio di aver soddisfatto la vostra curiosit\u00e0 sui block, per domande e commenti visitate il <a href=\"http:\/\/forum.devapp.it\" target=\"_blank\">nostro forum<\/a> o utilizzate i commenti qui in basso.<\/p>\n<p>Alla prossima!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abbiamo gi\u00e0 parlato altre volte dei Block qui su devAPP, ad esempio in questo articolo introduttivo o&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[1111,1106,1110,1108,1107,1109],"class_list":["post-8984","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-__block","tag-block","tag-closure","tag-first-class-object","tag-programmare-objective-c","tag-struct"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8984","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\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=8984"}],"version-history":[{"count":16,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8984\/revisions"}],"predecessor-version":[{"id":9067,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8984\/revisions\/9067"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=8984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=8984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=8984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}