【问题标题】:Properties and ARC属性和 ARC
【发布时间】:2013-09-04 13:40:00
【问题描述】:

我正在使用 ARC 和 Cocos2d 2.0 作为静态库(它不使用 ARC 并且被编译为单独的目标)。我翻译了一个旧项目(没有 ARC),我想知道以这种方式声明属性是否有一些潜在的保留周期问题:

@interface PlayerData : NSObject <NSCoding> {
}


//Is ok to save this as if the game gets paused you may want to save this.
@property (readwrite, nonatomic) int numberOfHits;
@property (readwrite, nonatomic) bool everBeenHitInCurrentLevel;
@property (readwrite, nonatomic) int hitsForOneHearth;

我注意到我的各种场景会随着时间的推移而积累起来。此外,我在 CCLayer 方法(MyScene : CCLayer)的 release 方法中添加了一个 CCLOG 调用,它永远不会被调用。这就是我创建场景的方式(我使用“[CCDirector sharedDirector] replaceScene”方法替换它

+ (id) sceneWithLevelName:(LevelName)name
{
    CCScene *scene = [CCScene node];        
    ShooterScene * shooterLayer = [[self alloc] initWithId:name];
    [scene addChild:shooterLayer];


    return scene;    
}

编辑:当我意识到我愚蠢地没有包含一个带有对象的示例并且只使用原始数据类型时,我将在我的场景中粘贴一些元素的 sn-ps:CharacterSelection、ShooterScene 和 PlanetSelectionMenu:

//ShooterScene
@interface ShooterScene : CCLayer {
    HudLayer * hudLayer;
    ....
}

@property(readwrite, nonatomic) CCSpriteBatchNode* backgroundAndEnemiesBatchNode;
@property(readwrite, nonatomic) ShipEntity* playerShip;
... etc..


Please note that I do not declare member variables for properties like playerShip and backgroundAndEnemiesBatchNode beause, as far as I can understand, should suffice the property declaration (but please correct me if I am wrong or if the approach may cause issues). 

//CharacterSelectionScene
@interface CharacterSelectionScene : CCLayer {
    int currentlySelectedCharacterSpriteTag;
    CCSprite * lights;
    CCLayer * spritesLayer;    
    ...
}

//PlanetSelectionMenu
#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface PlanetSelectionMenu : CCLayer {
    CCLayer * backgroundLayer; // Added background images here
    CCLayer * alwaysPresentItems;
}

+ (id) scene;

@end

请注意,每次我从 PlanetSelectionMenu 转到 CharacterSelectionScene - 反之亦然 - 记忆都会增加。但是在这种情况下,我没有使用任何属性,而是“只是”将对象(CCSprites)添加到图层和批处理节点。

编辑 2:这是我在通过 Menu->CharacterSelection->PlanetSelectionScene 等运行时在分配中看到的内容。似乎 LiveBytes 平均为 4MB,因为当时我只看到一个场景,所以我假设没有保留周期。那我为什么会收到那些讨厌的 LOW 内存信息呢?

【问题讨论】:

  • 标准 C 语言数字数据类型(int、bool、double 等)无法创建保留循环,因为它们不指向任何内容。如果您期望一个对象被释放,而事实并非如此,那么您可能有另一个对象具有指向它的强指针。哪些对象具有指向MyScene 的强指针?你认为他们应该解除分配吗?
  • @AaronBrager 好点。我添加了一个更好的例子,包括对象而不是原始数据类型。我指的是 PlanetSelectionMenu 的 CCLayer(实际上是一个场景 - 选择了误导性名称)和 CharacterSelectionScene,因为当调用 replaceScene 时,dealloc 方法不会打印我添加的 CCLOG 语句。

标签: ios objective-c cocos2d-iphone automatic-ref-counting


【解决方案1】:

虽然现在的默认属性属性是strong,但它不能是那些导致保留周期的属性,因为它们是原始类型并且默认为assign

另外三种常见的引入保留循环的方法让人想起:

  • 您是否在任何地方实现委托模式 (@protocols)。您的委托是否总是在必要时使用弱引用?
-(id) initWithDelegate:(id) 目标 { ... _target = 目标; //_target 应该是一个弱引用 ... }
  • 您的任何子节点是否引用了它们的父节点?
-(id) initWithParent:(CCNode*) parentNode { ... _parent = 父节点; //_parent 应该是一个弱引用。 ... }
  • 做任何块引用self
^{[self callSomeMethod];}

应该使用对self的弱引用:

__weak typeof(self) selfReference = self; ^{[selfReference callSomeMethod];}

我通常发现使用 ARC 查找泄漏的最佳方法不是使用泄漏工具,而是使用分配工具。由于我的所有场景都倾向于在其符号中包含“场景”一词,因此我按场景一词进行过滤。

由于您使用的是replaceScene,因此您一次应该只有一个场景(过渡期间除外),因此您应该只能在对象摘要中看到一个对象。

如果您确实有一个悬而未决的场景,我通常会发现最好查看对象是否保留了历史。从这里开始,我将每个保留与相应的释放配对,直到找到保留而不释放我的场景的罪魁祸首。更常见的是,它不是带有块的明显保留循环,或者声明为强而不是弱的属性。

【讨论】:

  • 感谢您的详细回答。我在分配工具中应用了场景过滤器,幸运的是当时只有一个场景。但是,当我查看实时字节时,会发生一些奇怪的事情。尽管在分配特定场景时平均字节约为 4/5MB,峰值为 18MB,但仅当我分配了平均 4/5 MB 时,我才会收到低内存警告。我将在我的问题中添加一张图片,以便您了解我的意思。我还在 AppDelegate didReceive 内存警告方法中添加了可用内存的打印,但没有打印任何内容。
  • 好的。我退出 Instruments 并收到 lowMemory 警报。第一个有 48 MB,然后,一个又一个场景替换一个场景,它建立到 66 MB,然后崩溃。奇怪的是分配工具没有显示这个。
猜你喜欢
  • 2011-12-08
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多