Domanda

Nella maggior parte degli esempi vedo la seguente configurazione di IBOutlet:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *fooLabel;

@end

FooController.m:

@implementation FooController

@synthesize fooLabel;

@end

Ma funziona anche bene (avviso: nessuna proprietà e nessuna sintesi):



(Example B)

FooController.h:

@interface FooController : UIViewController {
    IBOutlet UILabel *fooLabel;
}

@end

FooController.m:

@implementation FooController

@end

Esistono degli aspetti negativi della definizione di IBOutlet come nell'esempio B? Come perdite di memoria? Sembra funzionare bene e preferisco non esporre gli IBOutlet come proprietà pubbliche in quanto non vengono utilizzati come tali, vengono utilizzati solo nell'implementazione del controller. Definirlo in tre punti senza una reale necessità non mi sembra molto ASCIUTTO (non ripetere te stesso).

È stato utile?

Soluzione

Su Mac OS X, le IBOutlet sono collegate in questo modo:

  1. Cerca un metodo chiamato set < OutletName >:. Se esiste, chiamalo.
  2. Se non esiste alcun metodo, cerca una variabile di istanza denominata < OutletName > ;, impostala senza conservare .

Su iPhone OS, le IBOutlet sono collegate in questo modo:

  1. call [oggetto setValue: outletValue forKey: @ " < OutletName > "]

Il comportamento del valore impostato per key è fare qualcosa del genere:

  1. Cerca un metodo chiamato set < OutletName >:. Se esiste, chiamalo.
  2. Se non esiste alcun metodo, cerca una variabile di istanza denominata < OutletName > ;, impostala e conservala .

Se usi una proprietà, cadrai in " Cerca un metodo chiamato set < OutletName >: ... " caso su entrambe le piattaforme. Se usi semplicemente una variabile di istanza, avrai un diverso comportamento di conservazione / rilascio su Mac OS X VS iPhone OS. Non c'è niente di sbagliato nell'usare una variabile di istanza, devi solo affrontare questa differenza di comportamento mentre passi da una piattaforma all'altra.

Ecco un link alla documentazione completa solo su questo argomento. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6

Altri suggerimenti

Su Mac OS X, le IBOutlet non vengono mantenute per impostazione predefinita. Questo è l'opposto del comportamento sul sistema operativo iPhone: sul sistema operativo iPhone, se non dichiari una proprietà che viene mantenuta e devi rilasciare questa proprietà nel metodo dealloc . Inoltre, il runtime a 64 bit può sintetizzare le variabili di istanza utilizzando le dichiarazioni di proprietà. Ciò significa che un giorno le variabili di istanza (con IBOutlet ) potrebbero essere omesse.

Per questi motivi è più omogeneo e compatibile creare sempre una proprietà e utilizzare IBOutlet solo nella proprietà. Sfortunatamente, è anche più prolisso.

Nel tuo primo esempio devi sempre rilasciare l'outlet nel metodo dealloc . Nel tuo secondo esempio devi rilasciare la presa solo con il sistema operativo iPhone.

Il risultato finale è esattamente lo stesso, ma devi tenere a mente alcune cose:

  • Quando si utilizzano i campi di istanza come punti vendita, NON è necessario rilasciarli in dealloc .

  • Quando si utilizzano proprietà che hanno l'attributo (trattenere), è necessario rilasciare la proprietà in dealloc (utilizzando self.property = nil o rilasciando la variabile di supporto). Questo rende molto più trasparente ciò che sta succedendo.

In realtà tutto si riduce alla stessa vecchia regola: " rilascerai ciò che alloci / mantieni " ;. Quindi nel caso in cui utilizzi un campo di istanza come outlet, non lo hai allocato / conservato, quindi non dovresti rilasciarlo.

È possibile che quegli esempi utilizzino il keep perché il codice di esempio sta allocando e inizializzando a livello di codice un UILabel e quindi aggiungendolo a UIView. È il caso di molti esempi, dal momento che imparare a usare Interface Builder non è spesso il loro punto.

Il secondo esempio (nessuna proprietà e nessuna sintesi) con IBOutlet viene utilizzato quando lo sviluppatore "assegna" UILabel (Button, View, ecc.) in Interface Builder - trascinando IBOulet sull'etichetta o su un altro componente View . A mio avviso, la precedente azione di trascinamento della selezione (Etichetta su vista) aggiunge anche la vista secondaria, l'etichetta a una vista - e così via. L'etichetta è mantenuta da una vista; una vista viene mantenuta da Window; La finestra è mantenuta dal proprietario del file. Il proprietario del file è di solito il tuo documento che viene avviato in main.

Noterai che quando esegui il tuo programma (aggiungendo un awakeFromNib

- (void)awakeFromNib
{
    [fooLabel blahblah];
}

che fooLabel ha già un indirizzo di memoria.

Questo perché l'etichetta è stata inizializzata da un bundle di file (il file pennino) usando non init ma initWithCoder. Il che essenzialmente deserializza il filestream su un oggetto e quindi imposta la variabile IBOutlet. (Stiamo ancora parlando del metodo IBOutlet).

Si noti inoltre che il suddetto metodo iOS utilizza il metodo Key Value

  call [object setValue:outletValue forKey:@"<OutletName>"]

che è il modello Osservatore / Osservabile. Tale modello richiede che l'oggetto osservabile faccia riferimento a ciascun osservatore in un insieme / matrice. Una modifica del valore ripeterà Set / Array e aggiornerà ugualmente tutti gli osservatori. Quel set manterrà già ogni osservatore, quindi la mancanza di conservazione in iOS.

Inoltre, il resto è speculazione.

Sembra che i casi in cui usi Interface Builder allora

 @property (nonatomic, retain) IBOutlet UILabel *fooLabel;

potrebbe eventualmente essere modificato in

@property (nonatomic, weak) IBOutlet UILabel *fooLabel;

o     @property (nonatomic, assegnato) IBOutlet UILabel * fooLabel;

E quindi non è necessario che sia rilasciato in un metodo dealloc. Inoltre soddisferà i requisiti OSX e iOS.

Questo è basato sulla logica e potrei mancare alcuni pezzi qui.

Tuttavia, potrebbe non importare se la vista è persistente per tutta la durata del programma. Considerando che un'etichetta in una finestra di dialogo modale (apri, chiudi, apri, chiudi) può in effetti avere un eccesso di ritenzione e una perdita per ciclo. E questo perché (di nuovo le speculazioni) ogni finestra di dialogo chiusa viene serializzata in un file system e persiste quindi posizione, dimensione e dimensione x, y, con le sue visualizzazioni secondarie, ecc. E successivamente deserializzata ... alla sessione successiva aperta (Opposto per dire minimiz o nascosto.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top