【问题标题】:Convert NSMutableArray to string and back将 NSMutableArray 转换为字符串并返回
【发布时间】:2011-02-02 07:14:27
【问题描述】:

在我当前的项目中,我面临以下问题:

应用程序需要与我的服务器交换数据,这些数据存储在 iPhone 上的 NSMutableArray 中。该数组包含 NSString、NSData 和 CGPoint 值。 现在,我认为实现这一点的最简单方法是将数组转换为格式正确的字符串,将其发送到我的服务器并将其存储在某个 mySQL 数据库中。此时我想从我的服务器请求代表我数组内容的字符串,然后将其实际转换回 NSMutablArray。

到目前为止,我尝试过这样的事情:

NSString *myArrayString = [myArray description];

现在我将此字符串发送到我的服务器并将其存储在我的 mySQL 数据库中。这部分效果非常好。

但是,当我从服务器接收到字符串时,我无法将其转换回 NSMutableArray。

有没有一种方法可以轻松地将数组描述转换回数组?不幸的是,到目前为止我找不到任何东西。 也许我从一开始就“序列化”数组的方式是错误的,有一种更聪明的方法可以做到这一点。

任何帮助表示赞赏。提前致谢。

【问题讨论】:

    标签: iphone nsmutablearray nsarray


    【解决方案1】:

    不要为此使用description,因为那是为了让它变成人类可读的“漂亮”格式。你想要的是对象的数据转储。

    您可能想要做的是利用 NSArray 执行 NSCoding 的事实来从中获取原始字节数组 -- NSData。 (这是您提到的序列化。)然后您可以将原始字节传输到您的服务器,使用 zip 压缩,或以 base-64 编码字节以通过 HTTP 发送查询字符串。要恢复阵列,您只需反转该过程即可。

    Stack Overflow 上有很多现有的问题和答案可以帮助您解决这个问题。以下是一对:

    How to convert NSArray to NSData?

    Converting NSData to base64

    【讨论】:

    • 谢谢。所以,如果我理解正确,我应该 1) 将数组转换为原始字节 = NSData 对象? 2) base64 编码 (1) 并将其作为字符串发送到我的服务器 3) 将 base64 字符串从我的服务器转换回原始字节 4) 将 (3) 转换为新数组 对吗?
    • 是的,你明白了。但就像我说的,根据底层传输,您可以跳过 base-64 编码步骤。但我猜你是通过 HTTP 与你的 MySQL 服务器通信,对吗?
    • 是的,实际使用 ASIHTTPRequest 并通过 POST 提交。
    • 那么,这可能就是要走的路。根据 base-64 编码字符串的长度...您可能无法发送几百万个编码字符或任何内容:)
    • 不,远不及那个:)
    【解决方案2】:

    好吧,我想我离得更近了。但是,我还没有完全做到这一点,因为在将数据转换回新数组时遇到了一些“EXC_BAD_ACCESS”。

    让我与您分享一些代码。下面应该负责将数组转换为 NSData,将 NSData 转换为 base64,反之亦然。

    @interface NSArray (dataConversion)
        + (NSArray*) arrayWithData:(NSData*) data;
        - (NSData*) convertToData;
    @end
    
    @implementation NSArray (dataConversion)
    
    
    - (NSData*) convertToData {
        unsigned n= [self count]; 
    NSMutableData* data = [NSMutableData dataWithLength: sizeof(unsigned)+
                           sizeof(id) *n];
    unsigned* p = [data mutableBytes];
    *p++= n;
    [self getObjects:(void*)p];
    return data;
    }
    
    + (NSArray*) arrayWithData:(NSData*) data {
    unsigned* p = (unsigned*)[data bytes];
    unsigned n = *p++;
    return [NSArray arrayWithObjects:(id*)p count:n];
    }
    
    @end
    
    @interface NSData (MBBase64)
    
    + (id)dataWithBase64EncodedString:(NSString *)string;     //  Padding '=' characters are     optional. Whitespace is ignored.
    - (NSString *)base64Encoding;
    @end
    
    
    static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    
    @implementation NSData (MBBase64)
    
    + (id)dataWithBase64EncodedString:(NSString *)string;
    {
    if (string == nil)
        [NSException raise:NSInvalidArgumentException format:nil];
    if ([string length] == 0)
        return [NSData data];
    
    static char *decodingTable = NULL;
    if (decodingTable == NULL)
    {
        decodingTable = malloc(256);
        if (decodingTable == NULL)
            return nil;
        memset(decodingTable, CHAR_MAX, 256);
        NSUInteger i;
        for (i = 0; i < 64; i++)
            decodingTable[(short)encodingTable[i]] = i;
    }
    
    const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
    if (characters == NULL)     //  Not an ASCII string!
        return nil;
    char *bytes = malloc((([string length] + 3) / 4) * 3);
    if (bytes == NULL)
        return nil;
    NSUInteger length = 0;
    
    NSUInteger i = 0;
    while (YES)
    {
        char buffer[4];
        short bufferLength;
        for (bufferLength = 0; bufferLength < 4; i++)
        {
            if (characters[i] == '\0')
                break;
            if (isspace(characters[i]) || characters[i] == '=')
                continue;
            buffer[bufferLength] = decodingTable[(short)characters[i]];
            if (buffer[bufferLength++] == CHAR_MAX)      //  Illegal character!
            {
                free(bytes);
                return nil;
            }
        }
    
        if (bufferLength == 0)
            break;
        if (bufferLength == 1)      //  At least two characters are needed to produce one byte!
        {
            free(bytes);
            return nil;
        }
    
        //  Decode the characters in the buffer to bytes.
        bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
        if (bufferLength > 2)
            bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
        if (bufferLength > 3)
            bytes[length++] = (buffer[2] << 6) | buffer[3];
    }
    
    realloc(bytes, length);
    return [NSData dataWithBytesNoCopy:bytes length:length];
    }
    
    - (NSString *)base64Encoding;
    {
    if ([self length] == 0)
        return @"";
    
    char *characters = malloc((([self length] + 2) / 3) * 4);
    if (characters == NULL)
        return nil;
    NSUInteger length = 0;
    
    NSUInteger i = 0;
    while (i < [self length])
    {
        char buffer[3] = {0,0,0};
        short bufferLength = 0;
        while (bufferLength < 3 && i < [self length])
            buffer[bufferLength++] = ((char *)[self bytes])[i++];
    
        //  Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
        characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
        characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
        if (bufferLength > 1)
            characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
        else characters[length++] = '=';
        if (bufferLength > 2)
            characters[length++] = encodingTable[buffer[2] & 0x3F];
        else characters[length++] = '=';    
    }
    
    return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
    }
    
    @end
    

    现在,我是这样使用它的:

    NSData *messageData = [[NSArray arrayWithArray:myNSMutableArray] convertToData];
    NSString *messageData = [messageData base64Encoding];
    

    messageData 是我现在发送到服务器的字符串。这很好用。

    现在反过来:

    NSData *arrayData = [NSData dataWithBase64EncodedString:serverResponseString]; //serverResponseString is the string returned from my server upon request
    
    NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:[NSArray arrayWithData:arrayData]]; //here it crashes and points to: "return [NSArray arrayWithObjects:(id*)p count:n];"
    

    我要么在这里遗漏了一些东西,要么完全偏离了轨道。任何帮助表示赞赏。谢谢。

    【讨论】:

    • 好的,我深入挖掘并创建了一个新项目,只是为了测试序列化和反序列化我的数组。我用与我在原始项目中的对象相似的对象填充了数组。你猜怎么了?有效。那么这告诉我什么呢?也许从我的服务器返回的字符串有问题?尚未确定。我会调查并报告。
    • 好的,这很快。我想我找到了问题所在。让我来解释:当我序列化我的数组,我得到类似这样的(不带引号)的字符串:“GwAAAPAWEgCQEhwAwBAcANAPHADwFhIAAFcZABBcGQCgUxsAQBAcALAhHADANRwA4CscADDcEACwERwAYDkcAPAUEgAQmBIAQFUbAOBaGwDQXRsAcB0cADBYGwAgUBsAkFUbAPBRGwDw / xsAMFkcAA ==”现在,如果我告诉我的应用程序序列化之后反序列化这个字符串的权利,它的工作原理。但是,当我想反序列化相同的字符串时,如 NSString *str = @"stringFromAboveHere";它崩溃了。明白我的意思吗?
    • 现在这很奇怪。经过更多的测试,我发现了一些有趣的东西。如上所述,我创建了一个新的测试应用程序。我用对象填充了这个应用程序。这些对象每次都是相同的,并且每次都位于相同的位置。但是,当我重新启动应用程序并序列化数组时,序列化的字符串每次都完全不同!这是为什么?我敢肯定,解决这个问题是摆脱我的问题的关键。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-11
    相关资源
    最近更新 更多