SendDataToAllPeers GameKit не отправляет пакеты достаточно быстро - PullRequest
0 голосов
/ 23 апреля 2011

Я пытаюсь отправить файлы по Bluetooth-соединению.

Я получил это на работу благодаря моему предыдущему посту , но этот метод не был эффективным с точки зрения памяти.

Весь файл был загружен в память перед отправкой, и это создало проблемы (и привело к сбою приложения) для файлов размером> ~ 20 МБ.Поэтому я предложил новый метод чтения только тех частей файла, которые мне нужны в определенное время, создания пакетов из данных, их отправки и повторения процесса для каждого фрагмента файла размером 8 КБ.

Поэтому я создал метод класса, который генерирует пакет, сообщает контроллеру, что пакет доступен (через протокол), и повторяет этот процесс для каждого доступного пакета.

Вот код для генератора пакетов:

+ (void)makePacketsFromFile:(NSString *)path withDelegate:(id <filePacketDelegate>)aDelegate {
    if (![[NSFileManager defaultManager] fileExistsAtPath:path] || aDelegate == nil) return;

    id <filePacketDelegate> delegate;
    delegate = aDelegate;

    const NSUInteger quanta = 8192;
    uint filesize;

    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
    filesize = [[fileAttributes objectForKey:NSFileSize] intValue];

    int numOfPackets = (int)ceil(filesize/quanta);
    if (numOfPackets == 0) numOfPackets = 1;

    NSLog(@"filesize = %d, numOfPackets = %d or %.3f", filesize, numOfPackets, (float)ceil(filesize/quanta));

    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];

    int offset = 0;
    int counter = 0;

    while (counter != (numOfPackets + 1)) {
        uint len = (filesize < quanta) ? filesize : quanta;
        if (counter == numOfPackets) {
            len = filesize - offset;
        }
        [handle seekToFileOffset:offset];
        NSData *fileData = [handle readDataOfLength:len];
        file_packet *packet = [[file_packet alloc] initWithFileName:[path lastPathComponent] ofType:0 index:counter];

        packet.packetContents = fileData;
        [fileData release];
        packet.checksum = @"<to be done>";
        packet.numberOfPackets = [NSString stringWithFormat:@"%d", numOfPackets];

        [delegate packetIsReadyForSending:packet];

        [packet release];

        offset += quanta;
        counter++;
    }

    [handle closeFile];

}  

И получение и отправка файла:

- (void)packetIsReadyForSending:(file_packet *)packet {
    NSData *fileData = [packet dataForSending];
    [self.connectionSession sendDataToAllPeers:fileData withDataMode:GKSendDataReliable error:nil];
}

- (void)sendFileViaBluetooth {
    [file_packet makePacketsFromFile:selectedFilePath withDelegate:self];
}

Однако использование памяти довольно велико.Не то, что я ожидал.

Я немного застрял в этом, поскольку не хотел бы ограничивать общий доступ по Bluetooth для файлов размером менее 20 МБ.

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

Изменить: Я думал об этом некоторое время и пришел к выводу, что не мой код вызывает проблему с выделением памяти, а стек GameKit для отправки пакетов.

Я думаю, что генерирую слишком многопакеты слишком быстрые, и я не думаю, что GameKit отправляет их достаточно быстро.

Поэтому я сейчас думаю о том, как узнать, когда GameKit отправил пакет, и сгенерировать еще один, когда GameKit подтвердит, что этоотправлено.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2011

В вашем коде есть одна проблема с управлением памятью:

NSData *fileData = [handle readDataOfLength:len];

fileData не было получено через NARC (метод, имя которого содержит new, alloc, retain, copy), поэтому вы не являетесь его владельцем, поэтому не выпускаете его.

[fileData release];

К сожалению.

Что касается использования памяти, следует учитывать, что даже если вы выпустите packet, вы не сможете точно сказать, что происходит внутри -[GKSession sendDataToAllPeers:withDataMode:error:]. Возможно, что метод внутренне создает автоматически высвобождаемые объекты, которые в конечном итоге освобождаются только после завершения +makePacketsFromFile:withDelegate:. Я предлагаю вам использовать новый пул автоматического выпуска в каждой итерации цикла:

while (counter != (numOfPackets + 1)) {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    uint len = (filesize < quanta) ? filesize : quanta;
    …
    counter++;

    [pool drain];
}

При этом любой автоматически выпущенный объект внутри этого цикла будет эффективно освобождаться в конце каждой итерации цикла.

0 голосов
/ 23 апреля 2011

Оформить NSInputStream . С его помощью вы можете открыть поток и одновременно считывать только буфер байтов.

...