{"id":7286,"date":"2011-07-25T11:47:27","date_gmt":"2011-07-25T09:47:27","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7286"},"modified":"2011-07-25T11:48:25","modified_gmt":"2011-07-25T09:48:25","slug":"l019-comunicazione-tra-oggetti-notifiche-e-delegati-in-objective-c","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/l019-comunicazione-tra-oggetti-notifiche-e-delegati-in-objective-c\/","title":{"rendered":"L#019 \u2013 Comunicazione tra oggetti: Notifiche e Delegati in Objective-C"},"content":{"rendered":"<p>Ciao a tutti. Oggi voglio parlarvi di un aspetto molto importante nella programmazione ad oggetti e che ha un&#8217;inestimabile valore anche nella programmazione per iOS: la comunicazione tra oggetti.<\/p>\n<p>Quando si ha a che fare con oggetti di varia natura, ci pu\u00f2 capitare di voler far comunicare alcuni di essi per ottenere specifiche funzionalit\u00e0. Solitamente, saremo noi stessi a creare una serie di classi che secondo la nostra architettura sono specificatamente progettati per comunicare tra loro. A questo proposito l&#8217;Objective-C ci mette a disposizione vari strumenti, ma due di essi sono i pi\u00f9 comuni in tutti i progetti e negli stessi SDK forniti da Apple per la programmazione per iOS e Mac OS: notifiche e delegati.<!--more--><\/p>\n<h4>Inviare e Ricevere Notifiche<\/h4>\n<p>Un modo molto semplice ed efficace per mettere in relazione due o pi\u00f9 oggetti senza che essi debbano conoscere alcun che dell&#8217;altro o degli altri, \u00e8 la classe NSNotificationCenter, che ci permette di far inviare e ricevere messaggi da e verso il centro notifiche di questa classe (che \u00e8 un Singleton), ed eseguire azioni di conseguenza.<\/p>\n<p>Il concetto fondamentale \u00e8 che la classe NSNotificationCenter si pone come intermediario tra i nostri oggetti per favorirne la comunicazione. Il NotificationCenter raccoglie le notifiche che gli oggetti inviano e le invia agli oggetti che si sono registrati per riceverle. Un&#8217;oggetto, infatti pu\u00f2 registrarsi presso il centro notifiche per ricevere una o pi\u00f9 notifiche. Inoltre pi\u00f9 oggetti possono registrarsi per ricevere la stessa notifica, il che rende ancora pi\u00f9 utile questo strumento. Quando un&#8217;oggetto si registra per ricevere una notifica, pu\u00f2 decidere di far effettuare ad un certo target un&#8217;azione (invocando un metodo del target, quindi).<\/p>\n<p>Per registrare un oggetto al ricevimento di una notifica basta una linea di codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(unMetodo) name:@\"Nome della notifica\" object:nil];\r\n<\/pre>\n<p>Con questo comando, otteniamo l&#8217;oggetto Singleton &#8220;defaultCenter&#8221;, quindi registriamo l&#8217;oggetto come osservatore di notifiche per la notifica il cui nome indichiamo nel parametro &#8220;name&#8221; (ma possiamo registrare come osservatore anche un oggetto che self contiene, ad esempio una sua variabile d&#8217;istanza) e indichiamo il metodo che va invocato quando l&#8217;osservatore riceve la notifica. Nel parametro &#8220;object&#8221; possiamo specificare un oggetto come mittente della notifica. In pratica, se una stessa notifica pu\u00f2 essere inviata da pi\u00f9 oggetti, possiamo decidere che un&#8217;osservatore effettui l&#8217;azione prevista solo se il mittente della notifica \u00e8 un determinato oggetto.<\/p>\n<p>Registrare un oggetto come osservatore per fargli ricevere notifiche \u00e8 dunque un processo molto molto semplice. Altrettanto semplice \u00e8 inviare una notifica al centro notifiche:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[[NSNotificationCenter defaultCenter] postNotificationName:@\"Nome della Notifica\" object:nil userInfo:nil];<\/pre>\n<p>Ancora una volta otteniamo l&#8217;oggetto Singleton &#8220;defaultCenter&#8221; e pubblichiamo una notifica con un dato nome. Possiamo aggiungere poi variabili addizionali, object (cio\u00e8 il mittente della notifica) e userInfo (un dizionario con le informazione dell&#8217;utente).<\/p>\n<p><strong>NOTA:<\/strong> \u00e8 consigliabile usare delle costanti come nomi per le notifiche in modo tale da evitare errori di scrittura nel codice e rendere pi\u00f9 agevole la modifica del nome della notifica in un secondo momento. Infatti, se volessimo cambiare il nome della notifica, in questo modo lo dovremmo fare solo una volta, nel file dove la costante \u00e8 stata dichiarata, mentre quando andiamo a scrivere il nome della costante come parametro per i metodi usati dal notificationCenter, non trattandosi di una stringa, il compilatore ci avvertir\u00e0 della presenza di eventuali errori di battitura.<\/p>\n<h4>Delegare non \u00e8 un male!<\/h4>\n<p>L&#8217;uso delle notifiche rende molto pi\u00f9 semplice la vita di noi poveri sviluppatori. D&#8217;altro canto, per\u00f2, inviare notifiche pu\u00f2 rivelarsi insufficiente per i nostri scopi. Ci ritroveremo allora nella condizione in cui delegare alcune azioni ad altri oggetti sia una pratica migliore. Questo accade specialmente quando vogliamo far si che una classe implementi dei metodi che permettano l&#8217;uso di un componente che abbiamo creato. In particolare, questa pratica si rivela utilissima quando chi user\u00e0 il nostro componente non siamo noi, o quando il nostro componente pu\u00f2 essere usato in tante classi diverse e a scopi diversi. Un&#8217;esempio di classe che \u00e8 solita delegare ad altri aggetti alcune azioni \u00e8 la classe UITableViewController, che delega alle sue sottoclassi il compito di fornire una fonte per le informazioni da mostrare nelle celle e di definire alcuni comportamenti delle celle (ad esempio, definire cosa succede quando una data cella viene selezionata).<\/p>\n<p>\u00c8 pratica comune definire i metodi da delegare nell&#8217;intestazione della classe che richiama il suo delegato per eseguire una data azione. Delegare dei metodi da implementare ad un&#8217;altro oggetto, implica anche definire quali sono questi metodi. Per farlo viene usata la parola chiava @protocol. Se ad esempio abbiamo una classe Box (Scatola) che vuole delegare al suo utente un metodo per definire cosa c&#8217;\u00e8 nella scatola, la sua dichiarazione e implementazione saranno qualcosa del tipo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@protocol BoxDelegate; \/\/ dichiara che esiste un protocollo chiamato BoxDelegate\r\n\r\n@interface Box : NSObject \r\n{\r\n    id<BoxDelegate> delegate_; \/\/ scrivere tra parentesi angolari il nome di un protocollo subito dopo il tipo di una variabile, significa dichiarare che quella variabile deve conformarsi al dato protocollo (cio\u00e8 adottarne i metodi)\r\n}\r\n\r\n@property (nonatomic, retain) id<BoxDelegate> delegate;\r\n\r\n- (void)riempiScatola;\r\n\r\n@end\r\n\r\n@protocol BoxDelegate <NSObject> \/\/ definiamo i metodi che compongono il protocollo\r\n\r\n- (NSArray *)inserisciOggetti;\r\n\r\n@optional\r\n- (void)svuotaScatola;\r\n\r\n@end\r\n<\/pre>\n<p>Nell&#8217;interfaccia di questa classe definiamo il protocollo con due metodi. I metodi che indichiamo nel protocollo, normalmente sono da implementare obbligatoriamente all&#8217;interno del delegato, ma possiamo decidere di rendere l&#8217;implementazione di alcuni di essi facoltativa dichiarandoli dopo la parola chiave @optional. La variabile delegate che abbiamo definito, deve conformarsi al protocollo, quindi implementarne i metodi obbligatori.<\/p>\n<p>Una possibile implementazione del metodo d&#8217;istanza della classe Box &#8220;riempiScatola&#8221;, potrebbe essere:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)riempiScatola\r\n{\r\n    NSArray *oggetti = [NSArray arrayWithArray:[self.delegate oggettiNellaScatola]];\r\n    \/\/ riempi la scatola\r\n}\r\n<\/pre>\n<p>Per implementare i metodi di un protocollo in una classe, dobbiamo dichiarare che la classe si conforma al dato protocollo. Per far ci\u00f2 ci basta scrivere nell&#8217;intestazione della classe, subito dopo il nome della sua superClasse, il nome del protocollo fra parentesi angolari &#8220;<nomeProtocollo>&#8220;. Se una classe si conforma a pi\u00f9 protocolli, i nomi di questi protocolli vanno scritti tra parentesi angolari separati da virgola. Ad esempio:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface MyBox : UIViewController <BoxDelegate, UIScrollViewDelegate>\r\n<\/pre>\n<p>Questa classe ovviamente dovr\u00e0 dichiararsi come delegato per un protocollo anche con un&#8217;istruzione del tipo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nBox *laMiaScatola = [[Box alloc] init];\r\nlaMiaScatola.delegate = self;\r\n<\/pre>\n<p>e ricordatevi di implementare opportunamente i metodi dichiarati nel protocollo come obbligatori!<\/p>\n<h4>Conclusioni<\/h4>\n<p>Mettere in comunicazione pi\u00f9 oggetti senza far interagire troppo una classe con un&#8217;altra non \u00e8 un compito semplice ma per fortuna i design patterns di delegazione e notifica ci vengono in aiuto. Questi non sono gli unici metodi per far comunicare pi\u00f9 oggetti fra loro ma sono i pi\u00f9 semplici e utili. Per un&#8217;ancora pi\u00f9 efficace comunicazione tra due o pi\u00f9 oggetti potreste utilizzare tranquillamente entrambi i metodi, delegando azioni e notificando eventi che ne inneschino altre.<\/p>\n<p>Che dire di pi\u00f9? Divertitevi a far comunicare tra loro i vostri oggetti! \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ciao a tutti. Oggi voglio parlarvi di un aspetto molto importante nella programmazione ad oggetti e che&#8230;<\/p>\n","protected":false},"author":539,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[843,842,841,840,835,844,620],"class_list":["post-7286","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-comunicazione-tra-oggetti-oop","tag-delegare-xcode","tag-delegate-objective-c","tag-delegati-objective-c","tag-nsnotificationcenter","tag-programmazione-ad-oggetti","tag-singleton"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7286","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\/539"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7286"}],"version-history":[{"count":11,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7286\/revisions"}],"predecessor-version":[{"id":7301,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7286\/revisions\/7301"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}