【问题标题】:iOS and NSCoding: is this the correct way to encode an NSMutableArray with custom objects?iOS 和 NSCoding:这是用自定义对象编码 NSMutableArray 的正确方法吗?
【发布时间】:2013-08-22 13:36:38
【问题描述】:

我的这个类有一个 NSMutableArray 的自定义 Cocos2d 对象,实现了 NSCoding 协议。

@interface PlayerData : NSObject <NSCoding> {
}

@property (readwrite, nonatomic) NSMutableArray *levelsStars; //Where levelsStars is filled with objects conforming to the NSCoding protocol.

对象为LevelData类型,继承自CCNode(一个Cocos2d类),符合NSCoding协议。

@interface LevelData : CCNode <NSCoding>

这是PlayerData中协议的实现。为了对自定义 Cocos2d 对象的NSMutableArray 进行编码和解码,符合NSCoding 对象:

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:[NSKeyedArchiver archivedDataWithRootObject:levelsStars] forKey:kLevelsStars];
}


-(id) initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        //Reading arrays:
        NSData * dataRepresentingLevelStars = [aDecoder decodeObjectForKey:kLevelsStars];
        if (dataRepresentingLevelStars!=nil) {
            NSArray * oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingLevelStars];
            if (dataRepresentingLevelStars!=nil) {
                levelsStars = [NSMutableArray arrayWithArray:oldSavedArray];
            }
            else
            {
                levelsStars = [[NSMutableArray array] initWithCapacity:10];
            }
        }

    }

    return self;
}

这种方法正确吗?我基于这个question / answer

编辑:我想我会在我的用例中添加更多细节

我的用户可以在不同的角色中进行选择,每个角色对应一个 PlayerData 对象,我计划将其存储在不同的文件中,并附加用户的游戏中心 ID(id-character1.archive、id-character2.archive 等)。

我确实保存了对象中字符的进度(例如分数、生命),包括 Cocos2d 对象的 NSMutableArray 自定义数组(在我的真实案例中,我确实有 5 个不同的数组,每个数组包含 20/30 个对象)。

【问题讨论】:

  • 请参考这个问题的答案。我希望这能回答你的问题。 stackoverflow.com/questions/2315948/…
  • 谢谢,但我不想使用 NSUserDefaults,因此我想问我对链接的解决方案的理解和实施是否正确..
  • 是的,它是正确的,但我建议你只将它用于小数据,否则它会很慢。
  • 谢谢建议,为什么很小?我的用例是:我的用户可以在不同的字符中进行选择,每个字符对应一个 PlayerData 对象,我保存对象中字符的进度(例如分数,生命),包括 Cocos2d 对象的 NSMutableArray 自定义数组(在我的真实如果我确实有 5 个不同的数组,每个数组包含 20/30 个对象)。
  • 5 个不同数组中的 30 个对象 = 150 个对象。 NSData 中的编码和解码速度很慢。我建议您将其存储在单独的 plist 文件中,而不是编码或解码,这将增加您的编码工作量,但会提高应用程序的性能。

标签: ios cocos2d-iphone nsmutablearray encode nscoding


【解决方案1】:

在您要取消归档的 PlayerData 对象的主要 init 方法中:

- (id)init {
    self = [super init];
    if (self) {
        self.levelsStars = [NSKeyedUnarchiver unarchiveObjectWithFile:pathToArchive];
        if (self.levelsStars == nil) self.levelsStars = [NSMutableArray array];
    }
}

这将对数组中的每个对象调用 initWithCoder:。并将它们拉回到一个可变数组中。

你会想要有一些方法来保存你的数据,同样在你的 PlayerData 对象上:

- (void)applicationDidEnterBackground:(NSNotification *)notification {
    [NSKeyedArchiver archiveRootObject:self.levelsStars toFile:pathToArchive];
}

这将对数组中的每个对象调用 encodeWithCoder: 并将它们写入文件。

【讨论】:

  • 据我了解,带有数据的存档和取消存档对象仅适用于 NSData 对象,并且鉴于我有一个带有自定义对象的 NSMutable 数组,我必须首先在 NSData 对象中对其进行编码(如在我的解决方案中) .我的解决方案有问题吗?
  • 您的 playerData 对象是您的最高级别对象,还是被其他类归档?
  • 在 cmets 中有人说你的方法很好,所以也许坚持下去,对我来说似乎过于复杂......
  • 有一个静态管理器类,根据当前选择的角色加载和卸载 PlayerData。就你所知,是否有针对此类问题的良好设计模式参考/教程?
  • 因此静态管理器应该是唯一调用 NSKeyedArchiver 或 NSKeyedUnarchiver 来归档播放器或播放器数组的管理器。那么自定义播放器类应该只实现 NSCoding 以及自定义 playerStars 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多