C'è un motivo per cui non posso inizializzare un CALayer al di fuori di una classe UIView?

StackOverflow https://stackoverflow.com/questions/805265

  •  03-07-2019
  •  | 
  •  

Domanda

Ho provato a noi CALayer come " sprite " in un'applicazione per iPhone su cui sto lavorando. Da quello che ho letto, sembra la cosa giusta da fare qui.

Quando installo il layer all'interno di una classe UIView sono in grado di mostrare il layer sullo schermo:     NSLog (@ " GameView initWithCoder ");

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"earth" ofType:@"png"];
earthImage = [[UIImage alloc] initWithContentsOfFile:imagePath];

earthLayer = [CALayer layer];
[earthLayer setContents:(id)[earthImage CGImage]];
[earthLayer setBounds:CGRectMake(0, 0, 32, 32)];
[earthLayer setPosition:CGPointMake(50, 50)];
[earthLayer setName:@"earth"];

[[self layer] addSublayer:earthLayer];

Tuttavia, quando provo a inizializzare il CALayer al di fuori di UIView, la mia applicazione si arresta in modo anomalo:

- (void)loadImage:(NSString*)fileName
{
  NSLog(@"GamePiece loadImage");
  NSArray* fileNameParts = [fileName componentsSeparatedByString:@"."];
  imageName = [[fileNameParts objectAtIndex:0] retain];
  NSString* ext = [fileNameParts objectAtIndex:1];

  NSString* imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:ext];
  image = [[UIImage alloc] initWithContentsOfFile:imagePath];

  layer = [CALayer layer];
  [layer setContents:(id)[image CGImage]];

  [layer setBounds:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)];
  [layer setPosition:CGPointMake(50.0f, 50.0f)];
  [layer setName:imageName];

  [fileNameParts release], fileNameParts = nil;
  [ext release], ext = nil;
}

NSLog(@"GameView initWithCoder");
earth = [[GamePiece alloc] init];
[earth loadImage:@"earth.png"];

[[self layer] addSublayer:[earth layer]];

Chiaramente sto facendo qualcosa di sbagliato qui, ma non so cosa sarebbe. Ho letto la Guida alla programmazione di animazioni di base e anche la Guida alla programmazione di applicazioni per iPhone, ma in realtà non sembrano parlare di come inizializzare un CALayer se non di passaggio.

Ho solo bisogno di una leggera spinta nella direzione corretta. Ho avuto una buona comprensione di tutto ciò che ho imparato quando si tratta di programmare l'iPhone. Sto riscontrando alcuni problemi con la grafica, i livelli e l'animazione.

Grazie in anticipo!

È stato utile?

Soluzione

Non possiedi il livello che ottieni dal metodo layer , quindi devi diventare proprietario. Qualche tempo dopo il ritorno del metodo, il layer viene deallocato e ciò causa il crash. Per curare questo:

layer = [[CALayer layer] retain]; // now we explicitly take ownership of this layer

Inoltre, non dimenticare di rilasciare il livello poiché lo possiedi ora:

// in your dealloc method
[layer release];

Dovresti leggere la Guida alla programmazione della gestione della memoria per Cocoa per maggiori dettagli su quando possiedi oggetti e quali sono le tue responsabilità in merito alla gestione della memoria.

Altri suggerimenti

Jason, grazie mille per aver risposto! Tuttavia, la tua risposta non sembra avere alcun effetto sull'esito del mio problema.

In realtà, la risposta "è" qualcosa legato alla gestione della memoria. Non il livello, ma il nome che ho ottenuto da NSArray dopo aver chiamato componentiSeparatedByString :. Se non rilasciare NSArray, il codice funziona correttamente. Quindi ho bisogno di fare una copia dell'NSString all'interno dell'array invece di usare l'oggetto nell'array.

Devo dire che non ho letto la Guida alla programmazione della gestione della memoria per Cocoa come suggerisci. Tuttavia, ho letto molti altri libri che parlavano dello standard utilizzato in Cocoa per gli oggetti creati e il loro conteggio dei conteggi. Ho una buona comprensione, ma a quanto pare, non è ancora buono quanto necessario.

Avevo davvero il sospetto che avrei dovuto copiare la stringa fuori dall'array, ma quando ha funzionato in UIView, ho solo pensato che fosse corretto. Il problema era che non lo tenevo come se fossi nel mio oggetto GamePiece.

Grazie per almeno avermi fatto guardare nella giusta direzione! Ero davvero alla fine con questo codice.

Per fare ciò che volevi, ecco come è possibile modificare il codice. In loadImage: usa questa riga per aggiungere il UIImage che hai caricato nel livello earth :

  

self.contents = image.CGImage;

CALayers hanno una proprietà contents che puoi impostare su CGImage piuttosto che affrontare il problema dell'uso delle chiamate Core Graphics per disegnare immagine nel contesto del livello.

Quindi nella sottoclasse principale UIView puoi aggiungere earth alla gerarchia di visualizzazioni in questo modo:

  

[self.layer addSublayer: earth];

Nota che earth è esso stesso un CALayer con un'immagine come contenuto, quindi la aggiungo direttamente come sublayer. L'altra cosa che dimentico sempre di fare è impostare la proprietà frame del layer. Altrimenti la sua larghezza e altezza saranno zero e quindi non mostrerà.

Nel tuo codice hai creato un livello ma non hai mai aggiunto il livello alla gerarchia della vista. C'è un albero se le viste (classe UIView) e le loro viste secondarie. La radice dell'albero è [UIWindow mainwindow] (nota che UIWindow è una sottoclasse di UIView . Ogni UIView ha una proprietà layer di tipo < code> CALayer che detiene effettivamente il suo contenuto visibile. UIView è solo un involucro attorno a CALayer per aggiungere elementi come la capacità di gestione del tocco.

L'idea importante che ti manca qui è che qualsiasi cosa sia visibile sullo schermo deve far parte di questo albero di viste con una UIWindow come radice e tutte le viste devono essere visibili (cioè avere il loro nascosta impostata su NO ) tra la finestra di livello superiore e il livello in questione. Solo allora uno strato sarà visibile sullo schermo. Quindi da qualche parte nel tuo codice devi aggiungere il tuo livello come sottostrato di qualcosa già visibile chiamando addSublayer: .

Nel tuo caso, suppongo che earth sia un'istanza di un CALayer e che cosa hai fatto all'interno del metodo loadImage: è crea un nuovo CALayer (con una chiamata a [CALayer layer] ) all'interno del livello earth ma non hai mai aggiunto quel nuovo layer a nulla non è mai diventato visibile. Quello che hai fatto invece è stato tentare di aggiungere il livello earth , che non ha ancora alcun contenuto, a quello che presumo sia un livello UIView

  

[[self layer] addSublayer: [earth layer]];

Un problema con questa linea è che sembra che tu pensi che layer sia una proprietà di earth . In realtà layer è un metodo di classe di CALayer che è un metodo di fabbrica per creare nuove istanze di CALayer . Ciò è confuso perché [self layer] sta effettivamente accedendo alla proprietà layer di un'istanza UIView . (Suppongo che self si riferisca a un'istanza di una sottoclasse UIView .

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