[英]Is there a reason I can't initialize a CALayer outside a UIView class?
我一直在嘗試將CALayers作為我正在研究的iPhone應用程序中的“精靈”。 從我一直在閱讀的內容來看,這似乎是正確的事情。
當我在UIView類中設置圖層時,我能夠讓圖層顯示在屏幕上: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];
但是,當我嘗試在UIView外部初始化CALayer時,我的應用程序崩潰了:
- (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]];
顯然我在這里做錯了,但我不知道那是什么。 我已經閱讀了“核心動畫編程指南”和“iPhone應用程序編程指南”,但他們似乎並沒有談論如何初始化CALayer而不是傳遞。
我只需要在正確的方向上輕輕推動。 在編程iPhone時,我對其他所有學到的東西都有了很好的理解。 我只是在圖形,圖層和動畫方面遇到了一些問題。
提前致謝!
您不擁有從layer
方法獲得的layer
,因此您必須擁有所有權。 在您的方法返回之后的某個時間,該層正在被釋放,這導致您的崩潰。 解決這個問題:
layer = [[CALayer layer] retain]; // now we explicitly take ownership of this layer
此外,不要忘記釋放圖層,因為您現在擁有它:
// in your dealloc method
[layer release];
您應該查看Cocoa內存管理編程指南,了解有關何時擁有對象以及您在內存管理方面的職責的更多詳細信息。
要做你想做的事,你可以在這里改變你的代碼。 在loadImage:
使用此行添加加載到earth
圖層的UIImage
:
self.contents = image.CGImage;
CALayers
有一個contents
,你可以設置一個屬性CGImage
,而不是通過使用核芯顯卡的麻煩會調用圖像繪制到該層的上下文。
然后在父UIView
子類中,您可以將earth
添加到視圖層次結構中,如下所示:
[self.layer addSublayer:earth];
請注意, earth
本身就是一個CALayer
其中包含圖像作為其內容,因此我將其直接添加為子圖層。 我總是忘記做的另一件事是設置圖層的frame
屬性。 否則它的寬度和高度將為零,因此不會顯示。
在您的代碼中,您創建了一個圖層,但從未將圖層添加到視圖層次結構中。 如果視圖(類UIView)及其子視圖有一棵樹。 樹的根是[UIWindow mainwindow](注意UIWindow是UIView
的子類。每個UIView
都有一個類型為CALayer
的layer
屬性,它實際上保存着它的可見內容UIView
只是CALayer
一個包裝器,用於添加觸摸處理能力之類的東西。
您在這里缺少的重要想法是,對於屏幕上可見的任何內容,它必須是UIWindow作為其根的所有視圖的一部分,並且所有視圖必須是可見的(即將其hidden
屬性設置為NO
)在頂層窗口和有問題的層之間。 只有這樣才能在屏幕上看到一個圖層。 因此,在代碼中的某處,您需要通過調用addSublayer:
將您的圖層添加為已經可見的內容的子圖層addSublayer:
。
在你的情況下,我假設earth
是CALayer
一個實例,你在loadImage:
method中所做的是在earth
層內創建一個新的CALayer
(調用[CALayer layer]
)但是你從未添加過新層到任何東西,所以它永遠不會變得可見。 你所做的是嘗試添加earth
層,它仍然沒有任何內容,我假設是UIView
的層
[[self layer] addSublayer:[earth layer]];
這一行的一個問題是你似乎認為layer
是earth
的屬性。 實際上, layer
是CALayer
的類方法,它是一種創建CALayer
新實例的工廠方法。 這很令人困惑,因為[self layer]
實際上正在訪問UIView
實例的layer屬性。 (我假設self
指的是UIView
子類的一個實例。)
傑森,非常感謝你的回應! 但是你的答案似乎對我的問題的結果沒有任何影響。
實際上,答案“是”與內存管理相關的東西。 不是Layer,而是在調用componentsSeparatedByString后從NSArray獲得的名稱。 如果我不釋放NSArray,代碼工作正常。 所以我需要在數組中復制NSString而不是使用數組中的對象。
我不得不說,我沒有按照你的建議閱讀Cocoa的內存管理編程指南。 但是,我已經閱讀了其他幾本書,其中討論了Cocoa中用於創建對象的標准及其保留計數。 我有一個公平的理解,但顯然,還沒有那么好。
我真的懷疑我應該將字符串復制出數組,但是當它在UIView中工作時,我只是認為它是正確的。 問題是,我沒有像我在GamePiece對象中那樣保持它。
感謝您至少讓我朝着正確的方向前進! 我真的很擅長這段代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.