【问题标题】:32/64 bit CGPoint Persistence in iOS across devicesiOS 中跨设备的 32/64 位 CGPoint 持久性
【发布时间】:2015-03-14 03:36:33
【问题描述】:

我继承了一些手绘代码,它记录了 CGPathRef 的点,然后将其转换为 CGPoints 的集合,最终以 NSData 的形式保存在我们的核心数据数据库中。

当前的转换代码如下所示:

    @interface StoredPath : NSObject
    {
        CGPathRef path;
    }


@implementation StoredPath

            - (NSArray *)getPoints
            {
                // Convert path to an array
                NSMutableArray *a = [NSMutableArray arrayWithObject:[NSNumber numberWithBool:YES]];

                CGPathApply(path, (__bridge void *)(a), saveApplier);
                if (![[a objectAtIndex:0] boolValue])
                {
                    return nil;
                }

                [a removeObjectAtIndex:0];

                return (a);
            }


        static void saveApplier(void *info, const CGPathElement *element)
        {
            NSMutableArray *a = (__bridge NSMutableArray*) info;

            int nPoints;
            switch (element->type)
            {
                case kCGPathElementMoveToPoint:
                    nPoints = 1;
                    break;
                case kCGPathElementAddLineToPoint:
                    nPoints = 1;
                    break;
                case kCGPathElementAddQuadCurveToPoint:
                    nPoints = 2;
                    break;
                case kCGPathElementAddCurveToPoint:
                    nPoints = 3;
                    break;
                case kCGPathElementCloseSubpath:
                    nPoints = 0;
                    break;
                default:
                    [a replaceObjectAtIndex:0 withObject:[NSNumber numberWithBool:NO]];
                    return;
            }

            NSNumber *type = [NSNumber numberWithInt:element->type];

            NSData *points = [NSData dataWithBytes:element->points length:nPoints*sizeof(CGPoint)];

            [a addObject:[NSDictionary dictionaryWithObjectsAndKeys:type, @"type", points, @"points", nil]];
        }

@end

这里要注意的重要部分是这一行:

NSData *points = [NSData dataWithBytes:element->points length:nPoints*sizeof(CGPoint)];

它将CGPoint 数据保存到一个紧凑的NSData 对象中,然后保存在我们的核心数据数据库中。

当应用程序的数据仅存在于单个设备上时,这很好。但现在这些数据已同步到其他设备,由于CGFloat(构成CGPoint 结构)在各种 iOS 设备上是 32 位或 64 位,它会崩溃。

在 64 位 iOS 设备上读取 32 位 NSData of CGPoints 时,字节不完全对齐并且绘图被破坏。当然,反之亦然(在 32 位 iOS 设备上读取 64 位 NSData of CGPoints)。

我一直在努力重构这个saveApplier: 方法,使其独立于平台并且可以轻松保存在核心数据中。

更新:

我正在考虑将这些点打包成一个"|" 分隔的字符串。

示例:pointsToSave = {442, 797.5}|{442, 797.5}|{442, 797.5}

NSString *pointsToSave = [[NSString alloc] init];

// Convert CGPoint's to a "|" separated string.
for (int i=0; i<nPoints; i++)
{
    pointsToSave = [pointsToSave stringByAppendingString:NSStringFromCGPoint(element->points[i])];

    if ((i+1)<nPoints)
    {
        pointsToSave = [pointsToSave stringByAppendingString:@"|"];
    }
}

它也使得平台之间的解析变得相当简单。

想法?

【问题讨论】:

    标签: ios objective-c core-data 64-bit cgpoint


    【解决方案1】:

    您可以选择floatdouble 作为要保存的数据类型。这将显式设置大小,因为 float 是 32 位,而 double 是 64 位。

    例如,如果你想要更紧凑,你可以这样做:

    float *floats = [self pointsToFloats:element->points];
    NSData *points = [NSData dataWithBytes:floats length:nPoints*sizeof(float)*2];
    
    free(floats); // Note will need to free, since assuming pointsToFloats uses malloc. Use delete if you use new.
    

    pointsToFloats 的定义类似于:

    - (float *)pointsToFloats:(CGPoint *)points; // Assuming this is straight-forward enough to implement
    

    这也意味着您也需要一些东西来解压数据。

    - (CGPoint *)floatsToPoints:(float *)floats;
    

    如果您需要更高的精度,也可以使用double

    当然还有其他方法可以做到这一点。

    【讨论】:

    • 我正在考虑将这些点打包成一个“|”分隔的字符串。 (更新了我的问题)。想法?
    • 您总是可以使用 JSON 字符串。要问自己的真正问题是“紧凑”的价值与方法的直观性。有时你不需要紧凑。
    • 我同意。在这种情况下,直观性和更容易调试比“紧凑”甚至纯粹的速度更受欢迎。
    • 您可以为 CGPathElement 创建一个类别,该类别体现了将其转换为 JSON 和从 JSON 转换的类型和点。或者,如果您不喜欢类别,请让必要的方法成为另一个类的成员。
    猜你喜欢
    • 1970-01-01
    • 2016-02-28
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2014-01-09
    • 2010-11-27
    • 1970-01-01
    相关资源
    最近更新 更多