开发者

Convert NSMutableArray to string and back

开发者 https://www.devze.com 2022-12-25 05:15 出处:网络
in my current project I\'m facing the following problem: The app needs to exchange data with my server, which are stored inside a NSMutableArray on the iPhone. The array holds NSString, NSData and C

in my current project I'm facing the following problem:

The app needs to exchange data with my server, which are stored inside a NSMutableArray on the iPhone. The array holds NSString, NSData and CGPoint values. Now, I thought the easiest way to achieve this, was to convert the array into a properly formatted string, send it to my server and store it inside some mySQL database. At this point I'd like to request the string, which represents contents of my array, from my server and then actually convert it back into a NSMutablArray.

So far, I tried something like this:

NSString *myArrayString = [myArray description];

Now I send this string to my server and store it inside my mySQL database. That part works really well.

However, when I receive the string from my server, I have trouble converting it back into a NSMutableArray.

Is there a method, which can easily convert array description back into an array? Unfortunately开发者_运维技巧 I couldn't find anything on that so far. Maybe my way of "serializing" the array is wrong right from the beginning and there is a smarter way to do this.

Any help appreciated. Thanks in advance.


Don't use description for that, since that's for getting it into a human-readable "pretty" format. What you want is a data dump of the object.

What you might want to do instead is leverage the fact that NSArray does NSCoding to get an array of raw bytes from it -- NSData. (This is the serialization you mentioned.) You could then transfer the raw bytes to your server, use zip compression, or encode the bytes in base-64 to send in a query string over HTTP. To recover the array, you'd just reverse the process.

There are plenty of existing questions and answers on Stack Overflow to help you out with that. Here are a couple:

How to convert NSArray to NSData?

Converting NSData to base64


Alright, I think I got a bit closer. However, I'm not quite there yet, since I ran into some "EXC_BAD_ACCESS" when converting data back to a new array.

Let me share some code with you. The following is supposed to take care of converting the array to NSData, converting NSData to base64 and vice versa.

@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

Now, I use it like that:

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

messageData is the string I now send to my server. This works fine.

Now the other way round:

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];"

I'm either missing something here or completely off track. Any help appreciated. Thanks.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号