简体   繁体   English

iOS中跨设备的32/64位CGPoint持久性

[英]32/64 bit CGPoint Persistence in iOS across devices

I've inherited some freehand drawing code which records a CGPathRef of points that are then converted to a collection of CGPoints which eventually get saved within our core data DB as NSData . 我继承了一些徒手绘制的代码,其中记录了点的CGPathRef ,然后将这些点转换为CGPoints的集合,这些集合最终以NSData保存在我们的核心数据数据库中。

Current conversion code looks like this: 当前的转换代码如下:

    @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

The important part to notice here is the line: 这里要注意的重要部分是该行:

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

It preserves the CGPoint data into a compact NSData object, which then gets saved in our core data DB. 它将CGPoint数据保存到一个紧凑的NSData对象中,然后将其保存在我们的核心数据DB中。

This was fine when the app's data only lived on a single device. 当应用程序的数据仅存在于单个设备上时,这很好。 But now that this data is synced to other devices, it breaks down due to CGFloat (makes up CGPoint struct) being 32bit or 64bit on various iOS devices. 但是,由于此数据已同步到其他设备,由于在各种iOS设备上CGFloat (组成CGPoint结构)为32位或64位,因此该数据已CGPoint

When the 32bit NSData of CGPoints is read on a 64bit iOS device, the bytes don't quite align and the drawing gets mangled. 在64位iOS设备上读取NSData of CGPoints的32位NSData of CGPoints ,字节不完全对齐,并且图形被弄乱了。 The same of course happens in vice-versa (64bit NSData of CGPoints is read on a 32bit iOS device). 反之亦然( NSData of CGPoints 64位NSData of CGPoints在32位iOS设备上读取)。

I've been struggling to refactor this saveApplier: method in a way that is platform independent and can be easily saved in core data. 我一直在努力以saveApplier:独立于平台且可以轻松保存在核心数据中的方式重构这个saveApplier:方法。

Update: 更新:

I'm considering packing the points into a "|" 我正在考虑将点打包到"|" separated string. 分隔的字符串。

example: pointsToSave = {442, 797.5}|{442, 797.5}|{442, 797.5} 例如: 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:@"|"];
    }
}

It makes it fairly simple to parse between platforms as well. 它还使得在平台之间进行解析也相当简单。

Thoughts? 思考?

You could pick either float or double as the data type to save with. 您可以选择floatdouble作为要保存的数据类型。 This will explicitly set the size, since float is 32-bit and double is 64-bit. 这将明确设置大小,因为float是32位,而double是64位。

For example, if you want more compactness, you could do this: 例如,如果您想要更紧凑,则可以执行以下操作:

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.

Where pointsToFloats would be defined something like: pointsToFloats定义如下:

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

This also means you'll need something to unpack the data too. 这也意味着您还需要一些东西来解压缩数据。

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

You can also use double if you need more precision. 如果需要更高的精度,也可以使用double

There are of course others ways of doing this too. 当然,还有其他方法可以做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM