Nella costruzione delle nostre applicazioni può capitare ( come è accaduto a me ) di avere due View in cui dalla seconda di deve necessariamente modificare delle variabili usate nella prima.
Nel mio caso, in particolare, avevo le necessità, a seconda della pressione di una riga di una tabella, di visualizzare un Picker che modificasse un Dictionary presente nella prima classe ( quella della tabella per intenderci ). Insomma, dovevo usare stesse variabili da classi differenti. Inizialmente pensai di sfruttare le variabili globali ma, come i più reduci dalla programmazione sapranno, la variabili globali sono sempre “in linea di massima” sconsigliate. Le variabili dovrebbero avere, sempre, il campo di applicazione più piccolo possibile. Aumentandolo, infatti, non si farebbe altro che ottenere più codice in grado di modificare potenzialmente la variabile e aumentare la complessità generale del codice, le difficoltà nella correzione di eventuali errori e il riutilizzo dello stesso.
Cercando in rete mi sono imbattuto in una soluzione, secondo me, da tener presente e che ho correttamente utilizzato. In parole povere viene sfruttato il delegate per trasferire i dati tra le classi.
Diamo uno sguardo al codice per capire al meglio le operazioni da compiere.
Innanzitutto diamo per scontato di avere due classi ClasseA e ClasseB.
Nel delegate della nostra applicazione effettuiamo le seguenti dichiarazioni:
#import
@class ClasseA, ClasseB; // Le nostre due classi
@interface PickerAppDelegate : NSObject {
UIWindow *window;
UITabBarController *tabBarController;
NSMutableString *variabile; // Ammettiamo che sia questa la variabile da condividere
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@property (nonatomic, retain) NSMutableString *variabile;
@end
Nel file di implementazione (.m) del nostro Delegate sintetizziamo semplicemente la variabile:
@synthesize variabile;
Accediamo ora alle nostre due classi ClasseA e ClasseB in cui dobbiamo utilizzare la variabile. In queste due classi importiamo il delegate nel solito modo
#import "NostroProgettoDelegate.h"
Dove dobbiamo utilizzare la variabile “condivisa” effettuiamo questa dichiarazione:
NostroProgettoDelegate *mainDelegate = (NostroProgettoDelegate *)[[UIApplication sharedApplication]delegate];
accediamo quindi alla nostra variabile condivisa in questo modo:
mainDelegate.variabile
effettuando su di essa tutte le operazioni necessarie. Nient’altro!
Descriviamo ora brevemente, per concludere, la classe UIApplication:
La UIApplication fornisce un punto centralizzato di controllo per le applicazioni per iPhone OS. Ogni applicazione ha una istanza UIApplication. Quando un’applicazione viene lanciata la UIApplicationMain viene richiamata. Questa classe, tra le altre cose, crea un’oggetto UIApplication singleton ( un’istanza a cui è associato un punto di accesso globale ) a cui è possibile accedere richiamando il metodo della classe sharedApplication. Inoltre la classe UIApplication contiene un metodo che consente di accedere al delegate della nostra applicazione, grazie quindi a questo metodo dell’oggetto, riusciamo ad accedere alla variabile creata nel delegate.
11 Responses to “T#037 – Accedere alle stesse variabili da classi diverse”
4 Maggio 2010
LucaCiao, volevo segnalarvi che questo metodo è sconsigliato da apple e non segue lo standard MVC. Se c’è una variabile che deve essere condivisa da più classi, si deve creare una classe singleton che conterrà queste variabili (una sorta di classe utility).
Mettendo le variabili nell’app delegate, si ha una dipendenza diretta nei confronti delle classi, che non saranno riusabili a meno di riaggiungere le variabili usate nel nuovo app delegate. Così facendo non si rispetta il pattern MVC, personalmente lo sconsiglio 🙂
Se volete posso segnalarvi un post su un altro blog (straniero) molto interessante dove viene spiegato tutto questo e anche il metodo correto. Scusatemi se mi permetto di contraddirvi, ma questo è un concetto fondamentale della programmazione seguendo il pattern mvc 🙂
4 Maggio 2010
Ignaziocpossiamo usare anche un approccio diverso.
supponiamo che B debba accedere alla variabile x della classe A.
si può dichiarare un nuovo membro all’interno della classe B (dotato di get e set o property) e subito dopo l’inizializzazione di B fare qualcosa tipo “classeB.nuovaVariabile = x”.
il secondo metodo meno generale è quello di creare un nuovo metodo initi, che accetta come parametro il valore della variabile x. in quest’ultimo caso non dobbiamo dimenticare di richiamare l’init della superclasse.
4 Maggio 2010
Luigi“classeB.nuovaVariabile = x”
ma ad X come accedi se è di un’altra classe….
4 Maggio 2010
Luigisi è una giusta osservazione ma in alcuni casi lo si può utilizzare e non lo abbiamo segnalato
è lo stesso discorso delle variabili globali 😀
4 Maggio 2010
Ignaziocx è una variabile della classe A, se nella classe A devi istanziare la classe B puoi usare il sistema che ho suggerito.
non mi vengono in mente esempi in cui da una classe A devi istanziare una classe B che deve accedere ad una variabile di una classe C, alla quale A non ha accesso.
4 Maggio 2010
davideconcordo appieno e consiglio questa lettura http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
5 Maggio 2010
Lucaesattamente il post che volevo indicare io 😉
10 Maggio 2010
Giovambattista FazioliSe si sono utilizzati a dovere i ViewController, è possibile navigare anche tra di essi, vedi: [self parentController] ad esempio…
26 Maggio 2010
DavideNelle mie applicazioni quando ho bisogno di avere accesso ad alcune variabili in modo globale creo un DataStore definito come singleton e cio’ mi da accesso alle variabili da dovunque mi trovo nel progetto.
Quindi sono pienamente d’accordo con Davide, specialmente in objective c…
8 Giugno 2011
gianmarcoPerchè quando provo ad accedere alla variabile xcode mi ritorna SIGABRT e termina…..qualcuno riesce a passarmi un codice sorgente almeno ho un qualcosa di funzionante da guardare? grazie e ciao
15 Aprile 2012
pastnon funziona: mi dà sempre null. Fose non ho messo nel punto giusto la dichiarazione (non ho capito dove vada messa di preciso)
NostroProgettoDelegate *mainDelegate = (NostroProgettoDelegate *)[[UIApplication sharedApplication]delegate];
Nella schermata di dettaglio dove vorrei comparisse la label contenente la variabile passata non compare nulla. Ho scritto così:
– (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.text;
AppDelegate *mainDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
//mainDelegate.variabile.text = @”alfonso2″;
//anche inserendo una scritta a caso da qui m dà null
variabilePassata.text = mainDelegate.variabile.text;
NSLog( @”Contenutoda vista %@”, mainDelegate.variabile );
// variabilePassata.text = @”giudtta”;;
}