{"id":7916,"date":"2011-11-03T10:11:43","date_gmt":"2011-11-03T09:11:43","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7916"},"modified":"2013-07-30T10:49:15","modified_gmt":"2013-07-30T08:49:15","slug":"l019-far-comunicare-oggetti-diversi-in-objective-c-quale-metodo-scegliere","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/l019-far-comunicare-oggetti-diversi-in-objective-c-quale-metodo-scegliere\/","title":{"rendered":"L#020 \u2013 Far comunicare oggetti diversi in Objective-C: quale metodo scegliere?"},"content":{"rendered":"<p>In questo articolo affronteremo un problema che \u00e8 stato spesso oggetto di richieste sul forum, vedremo infatti quali sono i modi in cui gli oggetti possono interagire e comunicare tra di loro.<\/p>\n<p>Sul <a href=\"http:\/\/forum.devapp.it\" target=\"_blank\">nostro forum<\/a> sono state poste spesso domande come: &#8220;come faccio per passare una variabile da una UIView A ad una UIView B?&#8221;  oppure &#8220;Dalla UITable A creo una UIView B e vorrei che visualizzasse alcuni dati presi dalla UITable A&#8230;&#8221;<\/p>\n<p>Queste domande sono solo casi particolari di comunicazione tra oggetti e la risposta \u00e8 &#8220;devi utilizzare uno dei modi possibili per far comunicare l&#8217;oggetto A con l&#8217;oggetto B&#8221;. Perch\u00e9 non bisogna dimenticare che UITable, UIVIew.. sono pur sempre oggetti, magari un po&#8217; particolari perch\u00e9 dotati di interfaccia grafica, ma pur sempre oggetti come un NSArray o una NSString.<!--more--><\/p>\n<h4>Quanti modi di comunicare?<\/h4>\n<p>Prima di tutto suddividerei i modi di comunicare in due categorie: la comunicazione diretta e la comunicazione indiretta. Vedremo con alcuni esempi e vantaggi \/ svantaggi di entrambe cosicch\u00e8 possiate decidere, di volta in volta, la vostra strategia.<\/p>\n<h4>Comunicazione diretta<\/h4>\n<p>La comunicazione diretta si ha quanto un oggetto A comunica direttamente ad un oggetto B senza l&#8217;utilizzo di intermediari.<\/p>\n<p>Un esempio di comunicazione diretta la incontriamo spessissimo nel nostro lavoro, come si vede in queste righe di codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nUIView *sampleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];\r\n[sampleView setBackgroundColor:[UIColor grayColor]];\r\n<\/pre>\n<p>Qui vediamo due esempi di comunicazione diretta, nel primo inviamo il messaggio initWithFrame: all&#8217;oggetto restituito dal metodo alloc: mentre nel secondo inviamo il messaggio setBackgoundColor: all&#8217;oggetto sampleView.<\/p>\n<p>Anche se pu\u00f2 sembrare scontato \u00e8 bene sottolineare che questo \u00e8 possibile solo perch\u00e9 l&#8217;oggetto che contiene il codice di questo esempio &#8220;sa&#8221; qual \u00e8 l&#8217;indirizzo dell&#8217;oggetto sampleView, o per usare un termine pi\u00f9 adatto &#8220;possiede un riferimento a sampleView&#8221;.<\/p>\n<p>Facciamo un secondo esempio, supponiamo di aver creato due nuove classi: Mittente e Destinatario, entrambe per comodit\u00e0 subclass di UIView<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nMittente *alice = [[Mittente alloc] init];\r\nDestinatario *bob = [[Destinatario alloc] init];\r\n<\/pre>\n<p>In questo caso alice potr\u00e0 comunicare con bob? La risposta \u00e8 no perch\u00e9 cos\u00ec come li abbiamo creati alice non ha nessun riferimento a bob e quindi non pu\u00f2 inviargli nessun messaggio.<\/p>\n<p>Per far s\u00ec che alice possa comunicare direttamente con bob abbiamo due possibilit\u00e0, la prima \u00e8 quella di fornirle un riferimento a bob come parametro di un metodo, ad esempio potremmo aggiungere alla classe Mittente questo metodo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)rendiTrasparente:(Destinatario *)dest {\r\n        [dest setBackgroundColor:[UIColor clearColor]];\r\n}\r\n<\/pre>\n<p>quindi basterebbe richiamare:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[alice rendiTrasparente:bob];\r\n<\/pre>\n<p>per far inviare ad alice un messaggio a bob chiedendogli di impostare il suo colore di sfondo a trasparente.<\/p>\n<p>Da notare che in questo caso alice da sola non sa comunicare con bob, quindi non \u00e8 un oggetto che opera in maniera indipendente, potremmo dire che \u00e8 un oggetto che offre il servizio di invio messaggi a chi ha un riferimento ad un oggetto di tipo Destinatario.<\/p>\n<p>La seconda possibilit\u00e0 \u00e8 forse pi\u00f9 complessa e rende alice in grado di lavorare in maniera indipendente. Per far questo possiamo memorizzare all&#8217;interno della classe Mittente un riferimento all&#8217;oggetto Destinatario.<\/p>\n<p>Modifichiamo quindi la classe Mittente aggiungendo una variabile di istanza di tipo Destinatario, e la settiamo subito dopo aver costruito l&#8217;oggetto:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nDestinatario *bob = [[Destinatario alloc] init];\r\n[alice setDestinatario:bob];\r\n<\/pre>\n<p>cos\u00ec facendo alice possiede un riferimento a bob e pu\u00f2 utilizzarlo in maniera indipendente in un metodo come:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)rendiTrasparente {\r\n        [self.destinatario setBackgroundColor:[UIColor clearColor]];\r\n}\r\n<\/pre>\n<p>Come si pu\u00f2 ben vedere il metodo non accetta pi\u00f9 nessun parametro quindi l&#8217;unico modo di modifirane il comportamento \u00e8 quello di cambiare il valore della variabile destinatario.<\/p>\n<h4>Comunicazione indiretta<\/h4>\n<p>In alcuni casi un oggetto pu\u00f2 comunicare con un altro anche se non ne possiede un riferimento diretto. Questo pu\u00f2 avvenire grazie ad un oggetto che assuma il ruolo di intermediario.<\/p>\n<p>\u00c8 necessario che i due oggetti che vogliono comunicare utilizzino lo stesso intermediario altrimenti la comunicazione non pu\u00f2 avvenire.<\/p>\n<p>Le classi singleton si prestano bene a tale scopo perch\u00e9 all&#8217;interno di un&#8217;applicazione pu\u00f2 essere presente solo una singola istanza della classe quindi non bisogna preoccuparsi di condividere un riferimento ad una particolare istanza.<\/p>\n<p>Nulla vieta di costruirsi le proprie classi singleton che facciano da intermediario, ma iOS ce ne mette due a disposizione che possono svolgere questo compito:  UIApplication e NSNotificationCenter;<\/p>\n<h5>AppDelegate<\/h5>\n<p>Possiamo ottenere un riferimento all&#8217;istanza singleton delle classe UIApplication tramite:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[UIApplication sharedApplication]\r\n<\/pre>\n<p>noi siamo per\u00f2 interessati non alla classe in s\u00e9, ma alla sua propriet\u00e0 delegate che \u00e8 un riferimento alla classe <nome_programmaAppDelegate> del nostro progetto.<\/p>\n<p>Supponiamo quindi che alice voglia comunicare a bob un numero intero ma non siano direttamente correlati, si pu\u00f2 aggiungere all&#8217;AppDelegate una variabile di tipo intero e, proprio per la visibilit\u00e0 globale di questa classe, alice potr\u00e0 memorizzarvi il valore che vuol comunicare a bob e bob potr\u00e0 leggerlo.<\/p>\n<p>La classe Mittente avr\u00e0 quindi un metodo come:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)memorizzaValore {\r\n        [[[UIApplication sharedApplication] delegate] setVariabileInt:42];\r\n}\r\n<\/pre>\n<p>mentre la classe Destinatario avr\u00e0 un metodo come:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)leggiValore {\r\n        int k;\r\n        k = [[[UIApplication sharedApplication] delegate] variabileInt];\r\n}\r\n<\/pre>\n<p>Io non sono un grande fan di questo approccio, perch\u00e9 ritengo che l&#8217;utilizzo dell&#8217;appdelegate come punto di convergenza tra oggetti diversi sia spesso una necessit\u00e0 dettata da una progettazione non ottimale, inoltre rovina la riusabilit\u00e0 del codice e tende a rendere l&#8217;applicazione pi\u00f9 confusa e meno gestibile; \u00e9 innegabile, per\u00f2, che si tratti di un approccio piuttosto diffuso e quindi mi \u00e8 sembrato giusto parnarne.<\/p>\n<h5>NSNotificationCenter<\/h4>\n<p>L&#8217;utilizzo della classe <strong>NSNotificationCenter<\/strong> \u00e8 un altro modo per far comunicare oggetti distanti e che non posseggono un riferimento diretto.<\/p>\n<p>L&#8217;utilizzo \u00e8 piuttosto semplice e risponde al design pattern &#8220;observer&#8221; (<a href=\"http:\/\/http:\/\/it.wikipedia.org\/wiki\/Observer_pattern\" target=\"_blank\">http:\/\/it.wikipedia.org\/wiki\/Observer_pattern<\/a>).<\/p>\n<p>L&#8217;oggetto che vuole ricevere una notifica si mette in ascolto di un particolare evento in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[[NSNotificationCenter defaultCenter] addObserver:self\r\n                                         selector:@selector(receiveTestNotification:)\r\n                                             name:@\"TestNotification\"\r\n                                           object:nil];\r\n<\/pre>\n<p>Cosa fa questo codice? Stiamo chiedendo alla classe singleton NSNotificationCenter di aggiungere l&#8217;oggetto self alla lista degli oggetti interessati alle notifiche &#8220;TestNotification&#8221; e quando questa arriver\u00e0 verr\u00e0 invocato il metodo receiveTestNotification:<\/p>\n<p>Quando l&#8217;oggetto non \u00e8 pi\u00f9 interessato a ricevere notifiche pu\u00f2 informare il NSNotification center in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[[NSNotificationCenter defaultCenter] removeObserver:self];\r\n<\/pre>\n<p>il quale provveder\u00e0 a toglierlo dalla lista degli observer.<\/p>\n<p>L&#8217;oggetto che vuole inviare la notifica dovr\u00e0 semplicemente utilizzare questo codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[[NSNotificationCenter defaultCenter] postNotificationName:@\"TestNotification\" object:nil];\r\n<\/pre>\n<p>per comunicare con tutti gli observer che qualcosa \u00e8 avvenuto.<\/p>\n<p>Un tipico utilizzo delle notifiche si ha con le UITableView. Nei progetti piccoli il viewcontroller dove risiede la tabella \u00e8 anche il suo datasource, ma in progetti pi\u00f9 grandi il datasource \u00e8 una classe separata. In questo caso come pu\u00f2 il datasource forzare un [table reloadData] se non ha un riferimento diretto alla tabella? Pu\u00f2 usare una notifica per comunicare indirettamente alla tabella che \u00e8 avvenuto un cambiamento nella sorgente dati, sar\u00e0 poi la tabella a decidere cosa fare di questa notifica.<\/p>\n<h4>Conclusioni<\/h4>\n<p>Abbiamo visto diversi modi di far parlare gli oggetti tra di loro, nessuno di questi \u00e8 migliore in senso assoluto rispetto agli altri, ciascuno ha le sue caratteristiche e i suoi casi d&#8217;uso, il mio consiglio \u00e8 quello di cercare di farsi una visione chiara dell&#8217;applicazione nella sua interezza, immaginando gli oggetti quasi come attori su un palcoscenico, ciascuno ad interpretare il suo ruolo, il nostro compito \u00e8 quello di sovraninterndere e coordinare la collaborazione tra gli attori, assegnando a ciascuno di essi la giusta parte senza mescolare i ruoli tra loro.<\/p>\n<p>buona programmazione!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questo articolo affronteremo un problema che \u00e8 stato spesso oggetto di richieste sul forum, vedremo infatti&#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":[935,959,960,835,958,235,620],"class_list":["post-7916","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-appdelegate","tag-comunicazione-tra-oggetti-objective-c","tag-guida-teorica-objective-c","tag-nsnotificationcenter","tag-receivetestnotification","tag-sharedapplication","tag-singleton"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7916","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=7916"}],"version-history":[{"count":10,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7916\/revisions"}],"predecessor-version":[{"id":10694,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7916\/revisions\/10694"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}