2009-04-30 5 views
3

私は私が働いているiPhoneアプリケーションで "スプライト"として私たちにCALayersを試みてきました。私が読んできたことから、それはここで正しいことのように思えます。UIViewクラスの外でCALayerを初期化できない理由はありますか?

UIViewクラス内でレイヤーを設定すると、レイヤーを画面に表示させることができます。 NSLog(@ "GameView initWithCoder");

私はUIViewの外のCALayerを初期化しようとしたときしかし、私のアプリケーションがクラッシュし
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]; 

- (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]]; 

は、明らかに私はここで何か間違ったことをやっているが、私はちょうどドンそれが何であるかは分かりません。私はCore Animation Programming GuideとiPhone Application Programming Guideを読んだことがありますが、実際にはCALayerを初期化する方法以外については話していません。

ちょうど正しい方向に穏やかなナッジが必要です。 iPhoneをプログラミングするときに私が学んだ他のすべてについて、かなり理解しています。グラフィックス、レイヤー、アニメーションに問題があります。

ありがとうございます!

答えて

2

layerメソッドから取得したレイヤーを所有していないため、所有権を取得する必要があります。あなたのメソッドが返ってから、レイヤーの割り当てが解除され、クラッシュが発生しています。この治すために:また

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

を、あなたは今、それを所有するため、層を解放することを忘れないでください:

// in your dealloc method 
[layer release]; 

あなたがオブジェクトとどのようなあなたを所有する場合の詳細についてはMemory Management Programming Guide for Cocoaを確認する必要があります責任はメモリ管理に関するものです。

0

Jason、ありがとうございました!しかし、あなたの答えは私の問題の結果に影響を与えていないようです。

実際、答えはメモリ管理に関連するものです。レイヤーではなく、componentsSeparatedByString:を呼び出した後にNSArrayから取得した名前です。私はNSArrayをリリースしない場合、コードは正常に動作します。だから私は配列内のオブジェクトを使用する代わりに配列内のNSStringのコピーを作成する必要があります。

あなたが提案したように、私はCocoaのメモリ管理プログラミングガイドを読んでいないと言わざるを得ない。しかし、私は作成されたオブジェクトと保持カウントのためにCocoaで使用されている標準について述べた他のいくつかの本を読んでいます。私は公正な理解を持っていますが、明らかに必要なほど良くはありません。

私は実際に配列から文字列をコピーする必要があるとの疑いがありましたが、UIViewで機能していたときには、それが正しいと仮定しました。問題は、私がGamePieceオブジェクトの中にいるように、私はそれを保持していないということでした。

少なくとも正しい方向を見ていただきありがとうございます!私はこのコードで本当に賢明だった。

+1

実際には、これまでのところラッキーだったとしても、レイヤーはまだ問題です。あなたはそれがivarの場合はそれを保持する必要があります。ファイル名については、私はそれを逃した。実際にそれを保持またはコピーする必要はありません。ちょうどそれを解放しないでください:)基本的に、あなたがあなたがそれらを作成しない限り(alloc/copy/new)あなたの関数の期間中にのみ使用するものは積極的に管理する必要はありません。あなたが抱きしめたいものは積極的に管理する必要があります(割り当てない/コピーしていない場合は、保持する必要があります)。 –

0

あなたが望むことを行うには、ここでコードを変更する方法があります。loadImage:使用時には、この行は、あなたがearth層にロードされUIImageを追加します。

self.contents = image.CGImage。

CALayersあなたはかなりコアグラフィックスを使用してのトラブルを経由するよりも、CGImageに設定することができますcontentsプロパティは、層のコンテキストに画像を描画するために呼び出しています。

[self.layerのaddSublayer:地球]

次に親UIViewサブクラスであなたは、このようなビュー階層にearthを追加することができます。

その内容は私は直接サブレイヤとして追加としてearth画像とCALayer自体であることに留意されたいです。もう忘れるのは、レイヤのframeプロパティを設定することです。さもなければ、その幅と高さはゼロになるので、表示されません。

コードでは、レイヤーを作成しましたが、レイヤーをビュー階層に追加したことはありません。ビュー(クラスUIView)とそのサブビューの場合はツリーがあります。ツリーのルートは[UIWindowメインウィンドウ](UIWindowがUIViewのサブクラスであることがわかります。各UIViewが実際に目に見える内容を保持しているタイプCALayerlayer性質を持っている。UIViewは、タッチ処理能力のようなものを追加するCALayer単なるラッパーであります。

あなたがここで欠落している重要なアイデアは、何かが画面上に表示されるためには、UIWindowをルートとしてすべてのビューが表示されている必要があります(つまり、 hiddenプロパティはNOに設定されています)トップレベルウィンドウと問題のレイヤーの間にレイヤーが表示されるだけで、レイヤーは画面上に表示されますので、コードのどこかでレイヤーをsomのサブレイヤとして追加する必要がありますaddSublayer:を呼び出すと既に表示されています。

あなたのケースでは、私はearthを想定していますがCALayerのインスタンスであり、何をloadImage:メソッドの内部で行っていることはearth層内の新しいCALayer[CALayer layer]を呼び出して)を作成しているが、その後、あなたはそれを追加しません何かに新しいレイヤーが見えるようになりました。 ;:あなたは代わりの試みは、まだすべてのコンテンツを持っていないearth層を、追加されたのは何、私が想定したものに[] [地層[自己層] addSublayer] UIViewの層

です

この行の1つの問題は、layerearthのプロパティであると思われるようです。実際にはlayerCALayerの新しいインスタンスを作成するファクトリメソッドであるCALayerのクラスメソッドです。これは、[self layer]が実際にUIViewインスタンスのlayerプロパティにアクセスしているので、混乱します。 (私はselfUIViewサブクラスのインスタンスを参照していると仮定しています)

関連する問題