{"id":7867,"date":"2011-10-20T11:35:54","date_gmt":"2011-10-20T09:35:54","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7867"},"modified":"2011-10-20T11:35:54","modified_gmt":"2011-10-20T09:35:54","slug":"introduzione-ad-arc-automatic-reference-counting","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/introduzione-ad-arc-automatic-reference-counting\/","title":{"rendered":"Introduzione ad ARC (Automatic Reference Counting)"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/guide-objective-c.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/guide-objective-c.jpg\" alt=\"guide-objective-c\" title=\"guide-objective-c\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-7875\" \/><\/a> Il nuovo compilatore Apple LLVM 3.0, introdotto con Xcode 4.2, introduce una funzionalit\u00e0 chiamata Automatic Reference Counting (ARC) estremamente interessante per noi sviluppatori. Essa ci aiuta a gestire in modo corretto la memoria di un&#8217;applicazione, permettendoci di creare applicazioni migliori e pi\u00f9 robuste.<\/p>\n<p>Prima di ARC, dovevamo chiamare manualmente e nei posti giusti i metodi retain\/release\/autorelease per assicurarci che gli oggetti rimanessero &#8220;in vita&#8221; esattamente quanto ci serviva. Purtroppo, dimenticare o inserire nel posto errato anche solo una chiamata a questi metodi dava origine a sprechi di memoria (che tipicamente crescono man mano che si usa l&#8217;applicazione) o addirittura a crash, cosa assolutamente intollerabile per un&#8217;applicazione professionale.<\/p>\n<p>Grazie ad ARC, gran parte di questo lavoro viene ora fatto in automatico e in modo migliore di quanto potremmo fare noi stessi. Vediamo come e perch\u00e9.<!--more--><\/p>\n<h4>Introduzione<\/h4>\n<p>Innanzitutto occorre fare una precisazione: <strong>ARC non \u00e8 un garbage collector<\/strong>. Il garbage collector funziona a run-time, cio\u00e8 durante l&#8217;esecuzione del programma. ARC, al contrario, lavora a compile-time, cio\u00e8 durante la compilazione. La differenza \u00e8 fondamentale: vediamo perch\u00e9.<\/p>\n<p>Il garbage collector \u00e8 a tutti gli effetti un &#8220;processo&#8221; che analizza continuamente la memoria alla ricerca di zone che non vengono pi\u00f9 utilizzate e che dunque possono essere deallocate. Questo ha le seguenti implicazioni:<\/p>\n<ol>\n<li>Il garbage collector consuma cicli di CPU.<\/li>\n<li>L&#8217;istante in cui un oggetto verr\u00e0 rilasciato non \u00e8 predicibile.<\/li>\n<\/ol>\n<p>ARC, invece, lavora a compile-time. In pratica, va lui stesso ad aggiungere al posto nostro le istruzioni necessarie per la gestione della memoria. D&#8217;altronde: chi meglio del compilatore sa dove devono essere inserite?<\/p>\n<p>ARC, dunque, per certi versi \u00e8 meglio di un garbage collector, anche se vedremo che ha alcuni limiti (per i pi\u00f9 impazienti: non gestisce i retain cycle).<\/p>\n<p>ARC \u00e8 disponile solo a partire da Xcode 4.2 e solo quando si usa il compilatore Apple LLVM 3.0. Inoltre, il deployment target deve essere impostato almeno a iOS 4 o a OS X 10.6, sebbene alcune funzionalit\u00e0 (le weak reference) siano supportate solo a partire da iOS 5 e OS X 10.7. ARC, inoltre, pu\u00f2 gestire solo oggetti e blocchi Objective-C, dunque se per qualche motivo ci trovassimo ad utilizzare le vecchie malloc dovremo continuare a liberarne la memoria manualmente.<\/p>\n<h4>In dettaglio<\/h4>\n<p>Il compilatore, quando ARC \u00e8 abilitato, sintetizza in automatico le chiamate ai metodi retain\/release\/autorelease. Ad esempio questo codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo *foo = [[Foo alloc] init];\r\n\/\/ do something with foo\r\nreturn;\r\n<\/pre>\n<p>viene automaticamente trasformato in:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo *foo = [[Foo alloc] init];\r\n\/\/ do something with foo\r\nobjc_release(foo); \/\/ funzionalmente equivalente alla vecchia [foo release];\r\nreturn;\r\n<\/pre>\n<p>In pratica non dobbiamo pi\u00f9 ricordarci di mettere la release, perch\u00e9 ci pensa il compilatore. Non solo: abbiamo la garanzia che lui la metta nel punto giusto, ovvero quando la variabile non viene pi\u00f9 utilizzata, non un attimo prima e non un attimo dopo.<\/p>\n<p>Un bel vantaggio: ARC riduce la possibilit\u00e0 che si verifichino quei nostri errori che si manifestavano in <strong>memory leak<\/strong> (zone di memoria occupate e mai pi\u00f9 rilasciate), <strong>dangling pointer<\/strong> (puntatori che si riferiscono ad aree di memoria non pi\u00f9 valide), <strong>double free<\/strong> (zone di memoria rilasciate pi\u00f9 volte) e addirittura crash dell&#8217;applicazione.<\/p>\n<p>Una curiosit\u00e0. Perch\u00e9 il compilatore ha inserito una chiamata a funzione, objc_release(), al posto di una chiamata al metodo release? Semplicemente perch\u00e9, pur essendo funzionalmente equivalente, una chiamata a funzione viene eseguita pi\u00f9 rapidamente rispetto all&#8217;invio di un messaggio. Non solo: il compilatore la pu\u00f2 individuare con maggiore semplicit\u00e0 e fare delle ulteriori ottimizzazioni. In questo articolo non ci interessano i dettagli, per\u00f2 \u00e8 interessante osservare che il codice scritto con ARC tipicamente \u00e8 addirittura pi\u00f9 efficiente di quello che potremmo scrivere a mano.<\/p>\n<p>Ma torniamo a noi. ARC permette di rimuovere molto codice che prima eravamo obbligati a scrivere. Ad esempio, nella maggior parte dei casi potremo evitare di scrivere i vecchi metodi dealloc, perch\u00e9 il compilatore \u00e8 in grado di sintetizzarli per noi. Addio dunque a queste vecchie istruzioni:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)dealloc {\r\n    [foo release];\r\n    [bar release];\r\n    [baz release];\r\n    [qux release];\r\n\r\n    [super dealloc];\r\n}\r\n<\/pre>\n<p>Non si tratta di un vantaggio da poco. Quante volte, ad esempio, ci \u00e8 capitato di dimenticare di rilasciare una variabile di istanza o di chiamare il metodo dealloc su super?<\/p>\n<p>In sintesi, usando ARC abbiamo questi vantaggi:<\/p>\n<ol>\n<li>Codice pi\u00f9 compatto e meno istruzioni da scrivere.<\/li>\n<li>Codice pi\u00f9 veloce.<\/li>\n<li>Codice con meno errori e dunque meno memory leak.<\/li>\n<\/ol>\n<p>Prima di concludere il paragrafo, vogliamo evidenziare che con ARC non solo non serve pi\u00f9 chiamare i vecchi metodi retain, release, autorelease e retainCount, ma addirittura diventa vietato. Infatti, se provassimo ad inserirli ci compariranno degli errori di compilazione piuttosto espliciti, come ad esempio &#8220;ARC forbids explicit message send of &#8216;retain'&#8221;.<\/p>\n<h4>Introduzione ai nuovi tipi di ownership<\/h4>\n<p>Prima di procedere dobbiamo fare una parentesi pi\u00f9 tecnica, fondamentale per capire il seguito dell&#8217;articolo e per padroneggiare davvero ARC.<\/p>\n<p>ARC introduce questi nuovi &#8220;lifetime qualifier&#8221; per gli oggetti:<\/p>\n<ul>\n<li><strong>strong<\/strong><\/li>\n<li><strong>weak<\/strong><\/li>\n<li><strong>unsafe unretained<\/strong><\/li>\n<li><strong>autoreleasing<\/strong><\/li>\n<\/ul>\n<p>Essi si usano nelle dichiarazioni in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo __strong *obj1 = ...;\r\nFoo __weak *obj2 = ...;\r\nFoo __autoreleasing *obj3 = ...;\r\nFoo __unsafe_unretained *obj4 = ...;\r\n<\/pre>\n<p>In estrema sintesi:<\/p>\n<ul>\n<li><strong>strong<\/strong> \u00e8 il qualificatore di default.<\/li>\n<li><strong>weak<\/strong> specifica una weak reference che viene automaticamente posta a nil quando l&#8217;oggetto a cui punta \u00e8 stato deallocato.<\/li>\n<li><strong>unsafe unretained<\/strong> \u00e8 simile a weak, ma non viene automaticamente posto a nil.<\/li>\n<li><strong>autoreleasing<\/strong> denota gli argomenti che sono passati per riferimento e che sono rilasciati automaticamente dopo il return.<\/li>\n<\/ul>\n<p>Spiegazione un po&#8217; fumosa? Facciamo un esempio pratico. Consideriamo questo codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo *obj1 = [[Foo alloc] init];\r\nFoo *obj2 = obj1;\r\nFoo __unsafe_unretained *obj3 = obj1;\r\n\/\/ do something with obj1, obj2 and obj3\r\nreturn;\r\n<\/pre>\n<p>Come viene &#8220;tradotto&#8221; da ARC? Indicativamente cos\u00ec:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo __strong *obj1 = [[Foo alloc] init];\r\nFoo __strong *obj2 = objc_retain(obj1);\r\nFoo __unsafe_unretained *obj3 = obj1;\r\n\/\/ do something with obj1, obj2 and obj3\r\nobjc_release(obj1);\r\nobjc_release(obj2);\r\nreturn;\r\n<\/pre>\n<p>Innanzitutto osserviamo che obj1 e obj2 vengono entrambi marcati con il qualificatore strong. Perch\u00e9? Perch\u00e9 non avendone specificati altri viene usato questo.<\/p>\n<p>Essendo obj2 di tipo <strong>strong<\/strong>, ARC vi aggiunge una retain esplicita sull&#8217;oggetto puntato. In altre parole, sia obj1 sia obj2 diventano &#8220;proprietari&#8221; dell&#8217;oggetto da essi puntato. Naturalmente, dal momento che entrambi obj1 e obj2 sono diventati proprietari dell&#8217;oggetto, dovranno poi rilasciarlo quando non gli servir\u00e0 pi\u00f9. Ma per fortuna non dobbiamo occuparcene noi: \u00e8 proprio il compito di ARC, che inserisce le chiamate objc_release() appena prima di uscire dallo scope, ovvero appena prima della return. Ecco quindi svelato il significato del qualificatore strong: una variabile \u00e8 marcata in questo modo quando \u00e8 ARC a gestirne la memoria.<\/p>\n<p>obj3 invece, essendo <strong>unsafe unretained<\/strong>, si comporta in modo diverso. Come possiamo osservare, obj3 non diventa &#8220;proprietario&#8221; dell&#8217;oggetto puntato, perch\u00e9 non fa su di esso una retain esplicita. In pratica, quando dichiariamo una variabile unsafe unretained stiamo dicendo ad ARC che non deve occuparsi lui della gestione della memoria. Attenzione per\u00f2: quando entrambi obj1 e obj2 saranno stati rilasciati, obj3 continuer\u00e0 a puntare ad un&#8217;area di memoria non valida. Poco grave in questo esempio specifico, ma \u00e8 una cosa a cui conviene prestare molta attenzione. Per fortuna ci viene in aiuto il qualificatore weak. Usandolo al posto di unsafe unretained, ARC farebbe la &#8220;traduzione&#8221; in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nFoo __strong *obj1 = [[Foo alloc] init];\r\nFoo __strong *obj2 = objc_retain(obj1);\r\nFoo __weak *obj3 = obj1;\r\n\/\/ do something with obj1, obj2 and obj3\r\nobjc_release(obj1);\r\nobjc_release(obj2);\r\nobj3 = nil; \/\/ <---------\r\nreturn;\r\n<\/pre>\n<p>Come possiamo vedere, dopo che entrambi obj1 e obj2 sono stati rilasciati, obj3 viene automaticamente posto a nil. Un bel vantaggio, anche se per poterne usufruire dobbiamo avere come target almeno iOS 5 o OS X Lion.<\/p>\n<p>Rissumendo, quindi, se vogliamo che ARC si occupi lui della gestione della memoria dobbiamo dichiarare l'oggetto come strong (oppure non dire niente, dal momento che questo \u00e8 il comportamento di default). Se invece vogliamo occuparcene noi, dobbiamo usare il qualificatore weak oppure, sui vecchi iOS 4 e Snow Leopard, unsafe unretained.<\/p>\n<p>A questo punto ci \u00e8 sicuramente sorto un dubbo: ma perch\u00e9 dovremmo usare weak o unsafe unretained? Perch\u00e9 non possiamo semplicemente demandare ad ARC il problema della gestione della memoria di tutte le variabili? Per via dei cosiddetti \"retain cycle\".<\/p>\n<h4>Retain cycle<\/h4>\n<p>Un \"retain cycle\" si presenta quando due oggetti si fanno (direttamente o indirettamente) una retain a vicenda. Questo comporta un memory leak, perch\u00e9 entrambi gli oggetti continuerebbero a \"vivere\" per tutta la durata dell'applicazione anche se non venissero pi\u00f9 utilizzati da nessun'altro.<\/p>\n<p>Il pi\u00f9 semplice retain cycle che si pu\u00f2 verificare \u00e8 questo:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-01.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-01.png\" alt=\"Introduzione-ad-ARC-Automatic-Reference-Counting-01\" title=\"Introduzione-ad-ARC-Automatic-Reference-Counting-01\" width=\"144\" height=\"200\" class=\"aligncenter size-full wp-image-7869\" \/><\/a><br \/>\n<\/center><\/p>\n<p>I nomi scelti per l'esempio non sono casuali. Un classico caso di retain cycle sono proprio i delegati. In tal caso, un oggetto (Foo nel nostro caso) mantiene un riferimento al suo delegato (FooDelegate). Se anche il delegato mantiene un riferimento di tipo strong a Foo (che \u00e8 appunto il comportamento di default), nessuno dei due verrebbe mai rilasciato:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-02.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-02.png\" alt=\"Introduzione-ad-ARC-Automatic-Reference-Counting-02\" title=\"Introduzione-ad-ARC-Automatic-Reference-Counting-02\" width=\"288\" height=\"200\" class=\"aligncenter size-full wp-image-7870\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Come possiamo risolvere il problema? Usando le \"weak reference\":<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-03.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-03.png\" alt=\"Introduzione-ad-ARC-Automatic-Reference-Counting-03\" title=\"Introduzione-ad-ARC-Automatic-Reference-Counting-03\" width=\"285\" height=\"200\" class=\"aligncenter size-full wp-image-7871\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Guardando il problema da un punto di vista pi\u00f9 generale, le linee guida Apple consigliano che nel caso in cui due oggetti abbiano una relazione padre-figlio, il genitore debba mantenere un riferimento di tipo strong verso il figlio. Se il figlio necessita di un riferimento al padre questo deve invece essere di tipo weak. In tal modo scampiamo alla trappola del retain cycle.<\/p>\n<p>Alcune volte i retain cycle sono pi\u00f9 subdoli. \u00c8 raro (ma non impossibile) avere catene di tre, quattro, cinque o pi\u00f9 oggetti che puntano l'un l'altro in un circolo vizioso. Meglio starci attenti, quindi.<\/p>\n<h4>Come cambiano le propriet\u00e0<\/h4>\n<p>Quanto visto vale per gli oggetti e le variabili, ma anche per le propriet\u00e0 esiste un approccio del tutto analogo.<\/p>\n<p>Il vecchio codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@property (retain) FooDelegate *obj;\r\n<\/pre>\n<p>adesso dovr\u00e0 diventare:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@property (strong) FooDelegate *obj;\r\n<\/pre>\n<p>Questo invece:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@property (assign) Foo *parentObj;\r\n<\/pre>\n<p>diventa:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@property (weak) Foo *parentObj;\r\n<\/pre>\n<h4>Le regole pi\u00f9 importanti<\/h4>\n<p>Alla luce di quanto detto, ecco le regole da seguire per poter compilare con ARC abilitato:<\/p>\n<ol>\n<li>alloc\/init degli oggetti: la creazione degli oggetti risulta invariata ma non si possono pi\u00f9 fare chiamate (dirette o indirette usando @selector) ai metodi retain\/release\/autorelease\/retainCount.<\/li>\n<li>Metodi di deallocazione: vengono di norma creati automaticamente e, come sempre, non va mai chiamata direttamente la dealloc. Se fosse necessario rilasciare altre risorse (allocate ad esempio con le vecchie malloc), si pu\u00f2 creare un metodo dealloc senza chiamare la [super dealloc], in quanto viene automaticamente aggiunta da ARC.<\/li>\n<li>Dichiarazione delle propriet\u00e0: utilizzare le parole chiave strong\/weak in sostituzione di retain\/copy\/assign. strong lo usiamo quando vogliamo demandare ad ARC il problema della gestione della memoria. weak (o unsafe unretained sui vecchi iOS 4 e Snow Leopard) quando dobbiamo evitare dei retain cycle.<\/li>\n<\/ol>\n<h4>Migrazione<\/h4>\n<p>Per rendere un vecchio codice compatibile con ARC, Xcode 4.2 ci fornisce un ottimo strumento semi-automatizzato. Lo troviamo a partire dal men\u00f9 Edit > Refactor > Convert to Objective-C ARC:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-04.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-04.png\" alt=\"Introduzione-ad-ARC-Automatic-Reference-Counting-04\" title=\"Introduzione-ad-ARC-Automatic-Reference-Counting-04\" width=\"509\" height=\"430\" class=\"aligncenter size-full wp-image-7872\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-04.png 509w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/Introduzione-ad-ARC-Automatic-Reference-Counting-04-300x253.png 300w\" sizes=\"auto, (max-width: 509px) 100vw, 509px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Il convertitore dapprima imposter\u00e0 il compilatore Apple LLVM 3.0, che come dicevamo nell'introduzione \u00e8 l'unico che attualmente supporta ARC. Questo passaggio tipicamente comporta il sorgere di errori o warning che dovremo correggere.<\/p>\n<p>Successivamente il codice verr\u00e0 reso compatibile con ARC, rimuovendo le chiamate ai metodi retain, release e autorelease e inserendo gli opportuni lifetime qualifier nella dichiarazione delle property. Inoltre, ogni NSAutoreleasePool verr\u00e0 sostituito con il nuovo statement @autoreleasepool.<\/p>\n<h4>Coesistenza di codice ARC con codice non-ARC<\/h4>\n<p>Prima di concludere osserviamo che \u00e8 possibile far coesistere codice ARC con codice non-ARC (interi framework, ma anche singoli file). Non entreremo nei dettagli in questo articolo, ma si tratta di una cosa molto utile per poter continuare ad utilizzare vecchie librerie stabili e consolidate negli anni senza doverle necessariamente migrare ad ARC.<\/p>\n<h4>Riferimenti<\/h4>\n<p>In rete purtroppo non vi sono ancora molte informazioni su ARC. I pochi articoli presenti sono estremamente tecnici. Ad ogni modo, a chi volesse approfondire l'argomento consigliamo questi:<\/p>\n<ul>\n<li><a href=\"http:\/\/clang.llvm.org\/docs\/AutomaticReferenceCounting.html\" target=\"_blank\">Automatic Reference Counting<\/a><\/li>\n<li><a href=\"http:\/\/developer.apple.com\/library\/mac\/#releasenotes\/ObjectiveC\/RN-TransitioningToARC\/_index.html\" target=\"_blank\">Transitioning to ARC Release Notes<\/a><\/li>\n<\/ul>\n<h4>Autori<\/h4>\n<p>Valerio Dutto e Marco Rocca sono i fondatori di Delite Studio S.r.l., societ\u00e0 specializzata nella creazione di applicazioni native di alta qualit\u00e0 per OS X e iOS. Il loro sito Web \u00e8 <a href=\"http:\/\/www.delitestudio.com\" target=\"_blank\">http:\/\/www.delitestudio.com<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Il nuovo compilatore Apple LLVM 3.0, introdotto con Xcode 4.2, introduce una funzionalit\u00e0 chiamata Automatic Reference Counting&#8230;<\/p>\n","protected":false},"author":544,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[8],"tags":[944,945,947,948,946,332,949,698],"class_list":["post-7867","post","type-post","status-publish","format-standard","hentry","category-guide-varie","tag-arc","tag-automatic-reference-counting","tag-dangling-pointer","tag-double-free","tag-garbage-collector","tag-memory-leak","tag-retain-cycle","tag-valerio-dutto"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7867","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\/544"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7867"}],"version-history":[{"count":9,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7867\/revisions"}],"predecessor-version":[{"id":7881,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7867\/revisions\/7881"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}