{"id":7086,"date":"2011-06-14T15:10:00","date_gmt":"2011-06-14T13:10:00","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7086"},"modified":"2011-06-14T15:10:00","modified_gmt":"2011-06-14T13:10:00","slug":"l018-objective-c-le-property-e-altre-amenita","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/l018-objective-c-le-property-e-altre-amenita\/","title":{"rendered":"L#018 &#8211; Objective-c: Le @property e altre amenit\u00e0"},"content":{"rendered":"<p>Tutti le usano, ma forse non tutti sanno a cosa servono. Sono l\u00ec, sotto la dichiarazione delle nostre variabili di istanza, ci fanno compagnia fin dal primo &#8220;hello world&#8221; che abbiamo realizzato ed accompagnano silenziosamente il nostro codice a suon di (nonatomic, retain). Vediamo quindi cosa sono e come possiamo sfruttare appieno la potenza delle @property nei nostri programmi.<\/p>\n<p>Iniziamo subito con una precisazione, le property sono facoltative, nessuno vi obbliga ad utilizzarle. Sono state introdotte con una oramai non pi\u00f9 tanto recente release di objective-c per rendere meno noiosa la vita a noi programmatori, facendosi carico di scrivere per noi alcune porzioni di codice, quindi studiatele, capitele e poi decidete cosa fare di volta in volta.<!--more--><\/p>\n<p>Vi sarete accorti che le variabili di istanza di una classe (da ora ivar) non sono direttamente accessibili da altre classi, questo accade perch\u00e9 di default sono dichiarate come &#8220;protette&#8221;, creiamo ad esempio una nuova classe, che derivi direttamente da NSObject e dichiariamo una variabile di tipo stringa:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface Classe1 : NSObject {\r\n\r\n    @protected\r\n\r\n    NSSTring stringaDiProva;\r\n\r\n}\r\n\r\n@end\r\n<\/pre>\n<p>in questo caso l&#8217;attributo @protected \u00e8 stato esplicitato, ma anche se non l&#8217;avessimo inserito la variabile sarebbe stata protetta di default.<\/p>\n<p>Poichi sanno che le variabili possono essere dichiarate anche come @public ed in questo caso diventano automaticamente accessibili anche da altre classi, anche se con una sintassi poco comune in obj-c che \u00e8 quella delle struct (nel corso di C vi avevo detto che gli oggetti sono in realt\u00e0 delle struct, no?)<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nmioOggetto->stringaDiProva;\r\n<\/pre>\n<p>Ma come ogni buon programmatore sa bene, fornire accesso alle ivar \u00e8 una pratica da evitare come la peste, perch\u00e9 la classe non pu\u00f2 avere il controllo sui dati che questa variabile assume&#8230;facciamo un esempio: supponiamo che per qualche strano motivo io decida di memorizzare una data come ivar di una classe non come NSDate, ma come 3 interi separati,<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint giorno\r\n\r\nint mese\r\n\r\nint anno\r\n<\/pre>\n<p>Quando qualcuno (anche io stesso) devo usare questa classe devo impostare &#8220;a mano&#8221; tutti e tre i valori usando un codice simile a questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nmioOggetto->giorno = 1;\r\n\r\nmioOggetto->mese = 5;\r\n\r\nmioOggetto->anno =  2011;\r\n\r\n\/\/oppure anche cos\u00ec\r\n\r\nmioOggetto->giorno = -1;\r\n\r\nmioOggetto->mese = 55;\r\n\r\nmioOggetto->anno =  -45;\r\n<\/pre>\n<p>come vedete l&#8217;utente \u00e8 libero di inserire qualsiasi dato e, cosa pi\u00f9 brutta la mia classe non ha modo di accorgersene se non quando acceder\u00e0 a queste variabili.<\/p>\n<p>Non sarebbe pi\u00f9 comodo allora fornire tre metodi come questo?<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)setGiorno:(int)day {\r\n\r\nif ((day > 0) && (day <= 31))\r\n\r\n    giorno = day;\r\n\r\n}\r\n\r\nelse {\r\n\r\n    printf(\"giorno non valido\");\r\n\r\n}\r\n<\/pre>\n<p>oppure addirittura un unico metodo che faccia pi\u00f9 o meno questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)setDataWithGiorno:(int)day andMonth:(int)month andYear:(int)year {\r\n\r\n   if ((day == 31) && (month == 1))\r\n\r\n      giorno = day;\r\n\r\n      mese = month;\r\n\r\n    }\r\n\r\n    \/\/altri test logici.....\r\n\r\n}\r\n<\/pre>\n<p>Questa tecnica si chiama \"incapsulamento\" ed \u00e8 uno dei pilastri fondamentali dell'OOP. (<a href=\"http:\/\/it.wikipedia.org\/wiki\/Programmazione_orientata_agli_oggetti#Incapsulamento\" target=\"_blank\">http:\/\/it.wikipedia.org\/wiki\/Programmazione_orientata_agli_oggetti#Incapsulamento<\/a>)<\/p>\n<p>Vi starete chiedendo \"e questo che c'entra con le property?\" c'entra eccome! Perch\u00e9 visto che l'incapsulamento \u00e8 cosa buona e giusta, tutti i programmatori hanno preso l'abitudine di nascondere sempre le variabili di istanza e fornire sempre due metodi accessori (una italianizzazione di \"accessor methods\", peccato che \"accessorio\" in italiano non significhi \"che accede\")<\/p>\n<p>Per esempio per una banale ivar di tipo int si scrive di solito:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(int)nomeVariabile {\r\n\r\n   return nomeVariabile;\r\n\r\n}\r\n\r\n-(void)setNomeVariabile:(int)value {\r\n\r\n    nomeVariabile = value;\r\n\r\n}\r\n<\/pre>\n<p>Nel caso di ivar di tipi pi\u00f9 complessi, come gli oggetti dell'sdk di iOS, i metodi sono pi\u00f9 corposi perch\u00e9 devono tenere conto anche del problema della memoria e del retaincount degli oggetti.<\/p>\n<p>Questo, ad esempio, \u00e8 il codice generato per una variabile di tipo NSString:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (NSString *)miaStringa\r\n\r\n{\r\n\r\n    return [[miaStringa retain] autorelease];\r\n\r\n}\r\n\r\n- (void)setMiaStringa:(NSString *)aMiaStringa\r\n\r\n{\r\n\r\n    if (miaStringa != aMiaStringa) {\r\n\r\n        [aMiaStringa retain];\r\n\r\n        [miaStringa release];\r\n\r\n        miaStringa = aMiaStringa;\r\n\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>moltiplicate questo codice per una cinquantina di variabili a classe ed avrete un'idea della mole di codice monotono e ripetitivo che bisogna scrivere.<\/p>\n<p>Esistono infatti anche programmi che lo fanno in automatico, dato il nome di una variabile e qualche altro parametro vi tirano fuori il codice esatto dei metodi accessori e questo \u00e8 quello che fa anche il costrutto <strong>@proprerty<\/strong> ed il suo fratello <strong>@synthesize<\/strong>, che si occupano di creare, a partire da alcuni parametri posti tra le parentesi si property, gli opportuni <strong>metodi getter e setter<\/strong>.<\/p>\n<p>Indipendentemente dai parametri utilizzati i nomi dei metodi seguono lo stesso standar che ho seguito io in questo articolo, il metodo getter ha lo stesso identico nome della ivar da accedere, mentre il setter si chiama <em>setNomeVariabile<\/em> dove NomeVariabile \u00e8 stato scritto con la iniziale maiuscola.<\/p>\n<p>Ma allora, visto che le ivar per le quali \u00e8 stata anche dichiarata una property hanno gli accessor methods gi\u00e0 prestabiliti non ci possiamo inventare una sintassi pi\u00f9 facile questa?<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[mioOggetto setNomeVariabileTemporanea:456];\r\n<\/pre>\n<p>Certo! Possiamo usare la notazione dotted, accedendo alla ivar tramite il codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nmioOggetto.nomeVariabile = 42;\r\n<\/pre>\n<p>Attenzione per\u00f2 a non confondere questo codice con questo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nmioOggetto->nomeVariabile = 42;\r\n<\/pre>\n<p>Nel secondo caso, infatti, accediamo ad una variabile @public di una classe, mentre nel primo stiamo \"sotto sotto\" richiamanto il metodo setter generato per noi automaticamente dalla @property.<\/p>\n<p>Vediamo infine quali sono le opzioni da fornire a @property affinch\u00e9 generi del codice secondo le nostre esigenze;<\/p>\n<ul>\n<li><strong>nonatomic<\/strong>: Utile nel caso di programmazione concorrente, se viene specificato questo attributo i metodi getter e setter non saranno thread-safe. In breve, se la variabile associata a questa property viene utilizzata contemporaneamente da metodi che girano su thread separati omettete nonatomic e obj-c si occuper\u00e0 di generare tutto il codice necessario per una gestione thread-safe.<\/li>\n<li><strong>readonly<\/strong>: la property sar\u00e0 valida in sola lettura, questo non si applica ovviamente all'accesso tramite gli accessor methods.<\/li>\n<li><strong>readwrite<\/strong>: \u00e8 il comporamento di default.<\/li>\n<li><strong>assign<\/strong>: quando il valore viene settato non viene fatto nessun tipo di retain sulla variabile, il codice generato per il setter \u00e8 questo:\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)setNomeVariabile:(NSString *)str {\r\n\r\n    nomeVariabile = str;\r\n\r\n}\r\n<\/pre>\n<\/li>\n<li><strong>copy<\/strong>: effettua una deep-copy dell'oggetto passato durante il set. il codice generato \u00e8 questo:\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)setNomeVariabile:(NSString *)str {\r\n\r\n    if(str != nomeVariabile) {\r\n\r\n       [nomeVariabile release];\r\n\r\n       nomeVariabile = [str copy];\r\n\r\n    }    \r\n\r\n}\r\n<\/pre>\n<\/li>\n<li><strong>retain<\/strong>: forse il pi\u00f9 usato, si limita a fare un retain dell'ogetto passato durante il set\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)setNomeVariabile:(NSString *)str {\r\n\r\n    if(str != nomeVariabile) {\r\n\r\n       [nomeVariabile release];\r\n\r\n       nomeVariabile = [str retain];\r\n\r\n    }    \r\n\r\n}\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>Spero che questo articolo vi sia utile, non esitate a contattarmi <strong>sul forum<\/strong> per qualsiasi domanda.<\/p>\n<p>IgnazioC<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tutti le usano, ma forse non tutti sanno a cosa servono. Sono l\u00ec, sotto la dichiarazione delle&#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":[773,774,778,779,670,241,775,776,777],"class_list":["post-7086","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-property-objective-c","tag-synthesize-objective-c","tag-assign-objective-c","tag-copy-objective-c","tag-corsi-di-programmazione-iphone-e-ipad","tag-ignazio-calo","tag-nonatomic-objective-c","tag-readonly-objective-c","tag-readwrite-objective-c"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7086","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=7086"}],"version-history":[{"count":2,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7086\/revisions"}],"predecessor-version":[{"id":7088,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7086\/revisions\/7088"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7086"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7086"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7086"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}