将NSCoding对象写入磁盘时性能下降

时间:2014-10-11 15:59:45

标签: ios objective-c

我正在开发一款iOS游戏,可以生成大块的2d磁贴,用户可以“无限地”移动。

仅供上下文使用:每个磁贴为32x32px,每个“块”包含4x4个磁贴(总共16个)。大多数磁贴都是空的,但是当某些东西被放置在磁贴上时,如果用户移动太远并且该块“卸载” - 我将块和磁贴数据保存到磁盘。

现在,块和磁贴都使用NSCoding协议。块可以保存NSArray个图块和一些布尔值,每个图块可以保存几个数字/布尔值。

这很有效 - 当块卸载它时会保存,当块再次加载时,它会被恢复。

但是,我注意到写入磁盘方法非常简短地杀死了我的FPS。因为当玩家移动时通常会有几个块被卸载在一起,并且当它们被卸载时,玩家已经移动得越来越多并且卸载 - 它会加起来。

我已经尽力确保只保存实际更改的块,并且我最好组织保存代码以避免在每次保存调用时实例化对象。

有没有更好的方法可以在不影响FPS的情况下保存数据?

  • 由于我通常会保存屏幕上看不到的数据,我可以这样做吗?
  • 是否有比NSCoding更快的方法,因为它只是每个类的一些浮点/布尔值?

这是Chunk保存代码:

-(void)saveToDisk {
    if( !self.hasUnsavedChanges ){
        NSLog(@"skipping saving chunk that has not changed");
        return;
    }
    [self.saveFile writeData:self withKey:self.savefileKey];
    self.hasUnsavedChanges = false;
}

-(void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:[NSNumber numberWithFloat:self.position.x] forKey:@"chunk.x"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.position.y] forKey:@"chunk.y"];
    [encoder encodeObject:tiles forKey:@"chunk.tiles"];
}

-(id)initWithCoder:(NSCoder *)decoder {

    Chunk *restore = [self init];

    NSNumber *xChunkNum = [decoder decodeObjectForKey:@"chunk.x"];
    NSNumber *yChunkNum = [decoder decodeObjectForKey:@"chunk.y"];
    restore.position = [Coord coordWithX:[xChunkNum intValue] Y:[yChunkNum intValue]];

    tiles = [decoder decodeObjectForKey:@"chunk.tiles"];

    return restore;
}

瓷砖代码:

-(void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:[NSNumber numberWithFloat:self.worldContextCoordinate.x] forKey:@"tile.world.x"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.worldContextCoordinate.y] forKey:@"tile.world.y"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.red] forKey:@"tile.color.red"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.green] forKey:@"tile.color.green"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.color.blue] forKey:@"tile.color.blue"];
    [encoder encodeObject:[NSNumber numberWithFloat:self.isSourceTile] forKey:@"tile.isSource"];forKey:@"tile.hasBlackNeighbor"];
}

-(id)initWithCoder:(NSCoder *)decoder {

    Tile *restore = [self init];

    NSNumber *xNum = [decoder decodeObjectForKey:@"tile.world.x"];
    NSNumber *yNum = [decoder decodeObjectForKey:@"tile.world.y"];
    [restore setWorldContextCoordinate:b2Vec2( [xNum floatValue], [yNum floatValue] )];

    NSNumber *red = [decoder decodeObjectForKey:@"tile.color.red"];
    NSNumber *green = [decoder decodeObjectForKey:@"tile.color.green"];
    NSNumber *blue = [decoder decodeObjectForKey:@"tile.color.blue"];

    restore.color = [CCColor colorWithRed:[red floatValue] green:[green floatValue] blue:[blue floatValue]];

    restore.isSourceTile = [decoder decodeObjectForKey:@"tile.isSource"];

    return restore;
}

1 个答案:

答案 0 :(得分:0)

鉴于您不需要担心影响UI或UX的完成事件,您应该能够异步运行这些事件。如果需要,您可以使用完成块执行此操作,以便您可以在必要时处理完成事件。

- (void)saveToDiskAsyncWithCompletion:(void(^)(BOOL finished))completion
{    
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NO), ^{
        [self saveToDisk];
        // or you could run any of your other operations here too.
        dispatch_async(dispatch_get_main_queue(), ^(void){
            completion(YES);
        });
    });
}