提前释放自动释放对象?
我有一个名为 GamePlay 的类,它看起来有点像这样:
@implementation GamePlay
-(id)init{
if((self = [super init])){
self.isAccelerometerEnabled = YES;
//ship defined in header
ship = [Ship shipWithParentNode:self];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageHeight = [ship spriteContentSize].height;
[ship setSpritePosition:CGPointMake(screenSize.width*0.5, imageHeight*0.5)];
}
return self;
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
CGPoint pos = [ship spritePosition];
pos.x = acceleration.x * 10;
[ship setSpritePosition:pos];
}
@end
因此,Ship 类看起来像这样:
@implementation Ship
+(id)shipWithParentNode:(CCNode *)parentNode{
return [[[Ship alloc] initWithParentNode:parentNode] autorelease];
}
-(id)initWithParentNode:(CCNode *)parentNode{
if((self = [super init])){
sprite = [CCSprite spriteWithFile:@"ship.png"];
SpriteLoader *spriteLoader = [SpriteLoader sharedSpriteLoader];
[spriteLoader addTextureAtlas:@"Spites_default.plist"];
CCAnimation *spriteAnimation = [CCAnimation animationWithFrames:[spriteLoader getSpriteFramesWithName:@"ship-" andAmount:[NSNumber numberWithInt:5]] delay:0.08f];
CCAnimate *anim = [CCAnimate actionWithAnimation:spriteAnimation];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:anim];
[sprite runAction:repeat];
[parentNode addChild:sprite z:0 tag:SHIP];
}
return self;
}
-(void)setSpritePosition:(CGPoint)point{
sprite.position = point;
}
-(CGPoint)spritePosition{
return sprite.position;
}
-(CGSize)spriteContentSize{
return sprite.contentSize;
}
@end
GamePlay 初始化 < strong>Ship 很好,继续修改 Ship 内的 CCSprite,在模拟器中,一切都很好。当在设备上运行它时,我们会获得加速度计输入。在加速度计方法中,第一行使程序崩溃,因为船不再存在。如果我在调试器中在加速度计方法的第一行设置断点,我会看到以下内容: self = (游戏玩法 *)
-> Ship = (Ship *) 0x004701e0
如果我继续运行程序,我会收到以下消息: 消息发送到已释放实例 0x4701e0
但我不确定为什么它被释放......大概是 0x004701e0 == 0x4701e0 ?
非常感谢, 本
I've got a class called GamePlay, which looks somewhat like this:
@implementation GamePlay
-(id)init{
if((self = [super init])){
self.isAccelerometerEnabled = YES;
//ship defined in header
ship = [Ship shipWithParentNode:self];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageHeight = [ship spriteContentSize].height;
[ship setSpritePosition:CGPointMake(screenSize.width*0.5, imageHeight*0.5)];
}
return self;
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
CGPoint pos = [ship spritePosition];
pos.x = acceleration.x * 10;
[ship setSpritePosition:pos];
}
@end
So, the Ship class looks something like this:
@implementation Ship
+(id)shipWithParentNode:(CCNode *)parentNode{
return [[[Ship alloc] initWithParentNode:parentNode] autorelease];
}
-(id)initWithParentNode:(CCNode *)parentNode{
if((self = [super init])){
sprite = [CCSprite spriteWithFile:@"ship.png"];
SpriteLoader *spriteLoader = [SpriteLoader sharedSpriteLoader];
[spriteLoader addTextureAtlas:@"Spites_default.plist"];
CCAnimation *spriteAnimation = [CCAnimation animationWithFrames:[spriteLoader getSpriteFramesWithName:@"ship-" andAmount:[NSNumber numberWithInt:5]] delay:0.08f];
CCAnimate *anim = [CCAnimate actionWithAnimation:spriteAnimation];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:anim];
[sprite runAction:repeat];
[parentNode addChild:sprite z:0 tag:SHIP];
}
return self;
}
-(void)setSpritePosition:(CGPoint)point{
sprite.position = point;
}
-(CGPoint)spritePosition{
return sprite.position;
}
-(CGSize)spriteContentSize{
return sprite.contentSize;
}
@end
GamePlay initialises the Ship fine and continues to modify the CCSprite within Ship, and in the simulator, all is well. When it comes to running it on a device, we get accelerometer input. In the accelerometer method, the first line crashed the program because the ship no longer exists. If I look in the debugger with a breakpoint on the first line of the accelerometer method I see the following:
self = (GamePlay *)
-> ship = (Ship *) 0x004701e0
If I then continue the running of the program, I get this message:
message sent to deallocated instance 0x4701e0
But I'm not sure why it's been deallocated...And presumably 0x004701e0 == 0x4701e0 ?
Many thanks,
Ben
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您必须在
-[GamePlay init]
中保留
ship
(然后在dealloc中
,当然)。释放
它)You have to
retain
theship
in-[GamePlay init]
(and laterrelease
it indealloc
, of course).解释这个问题:
Ole 是正确的,Ship 需要保留在您发布的代码中。我个人认为这里存在设计问题。您的 Ship 类应该派生自 CCNode,并且您应该通过 addChild 将 Ship 添加到节点层次结构中。
如果 Ship 仅从 NSObject 派生,则最终得到的结果有点像“损坏的”节点层次结构:
中是 Ship 类的 sprite 由 Ship 类“管理”,但由 GamePlay 类保留。这意味着您有责任自己保留非 CCNode 类(例如 Ship)。以下是更简单、更符合 Cocos2D 的设计,因为它依赖于 Cocos2D 管理整个节点层次结构:
这样您就可以将 Ship 类作为子类添加到 GamePlay 类中。 Ship 类将其 CCSprite 实例添加到 self(Ship 类)。您可以(并且应该)删除在shipWithParentNode方法中传递的parentObject。在Cocos2D中,将一个节点的实例传递给另一个节点是非常危险的,您可能会想保留它,这可能会由于循环保留依赖关系而导致整个场景泄漏(a保留b,b保留a,两者都可以'不要放手)。
总体而言,这使您的节点层次结构更深一些,但更易于管理。您可以假设所有对象都派生自公共基类 (CCNode),并且您可以依靠 Cocos2D 在正确的时间以正确的顺序取消分配节点层次结构。
To explain the problem:
Ole is correct that the Ship needs a retain in the code you posted. Personally I see a design problem here. Your Ship class should derive from CCNode, and you should add the Ship to the node hierarchy via addChild.
If Ship derives just from NSObject, what you end up with is sort of like a "broken" node hierarchy:
The problem with that is that the Ship class' sprite is "managed" by the Ship class but retained by the GamePlay class. That means you're responsible for retaining the non-CCNode classes like Ship yourself. The following makes for a simpler and more Cocos2D conform design, because it relies on Cocos2D managing the entire node hierarchy:
That way you would add the Ship class as child to the GamePlay class. The Ship class adds its CCSprite instance to self (the Ship class). You can (and should) get rid of the parentObject passed in the shipWithParentNode method. In Cocos2D it is quite dangerous to pass an instance of a node to another node, you might be tempted to retain that, which can lead to leaking the entire scene because of circular retain dependencies (a retains b, b retains a, both can't let go).
Overall this makes your node hierarchy a bit deeper but it is much easier to manage. You can assume all objects to derive from a common base class (CCNode) and you can rely on Cocos2D deallocating the node hierarchy in the right order at the right times.