Конвертировать NSMutableArray в строку и обратно - PullRequest
1 голос
/ 30 марта 2010

в моем текущем проекте я сталкиваюсь со следующей проблемой:

Приложение должно обмениваться данными с моим сервером, которые хранятся в NSMutableArray на iPhone. Массив содержит значения NSString, NSData и CGPoint. Теперь я подумал, что самый простой способ достичь этого - преобразовать массив в правильно отформатированную строку, отправить его на мой сервер и сохранить в некоторой базе данных mySQL. На этом этапе я хотел бы запросить строку, которая представляет содержимое моего массива, с моего сервера, а затем фактически преобразовать ее обратно в NSMutablArray.

Пока что я пробовал что-то вроде этого:

NSString *myArrayString = [myArray description];

Теперь я отправляю эту строку на свой сервер и сохраняю ее в своей базе данных mySQL. Эта часть работает очень хорошо.

Однако, когда я получаю строку с моего сервера, у меня возникают проблемы с преобразованием ее обратно в NSMutableArray.

Существует ли метод, который может легко преобразовать описание массива обратно в массив? К сожалению, я пока не могу ничего найти по этому поводу. Возможно, мой способ «сериализации» массива неверен с самого начала, и есть более разумный способ сделать это.

Любая помощь приветствуется. Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 30 марта 2010

Не используйте description для этого, потому что это для перевода его в читаемый человеком "красивый" формат. То, что вы хотите, это дамп данных объекта.

Вместо этого вы можете использовать тот факт, что NSArray делает NSCoding, чтобы получить из него массив необработанных байтов - NSData. (Это упомянутая вами сериализация.) Затем вы можете передать необработанные байты на ваш сервер, использовать сжатие zip или закодировать байты в base-64, чтобы отправить строку запроса по HTTP. Чтобы восстановить массив, вам нужно просто изменить процесс.

Существует множество существующих вопросов и ответов по переполнению стека, чтобы помочь вам в этом. Вот пара:

Как преобразовать NSArray в NSData?

Преобразование NSData в base64

0 голосов
/ 30 марта 2010

Хорошо, я думаю, что стал немного ближе. Тем не менее, я еще не совсем там, так как я столкнулся с некоторым «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];"

Я либо что-то здесь упускаю, либо совсем не в курсе. Любая помощь приветствуется. Спасибо.

...