GameKit的sendDataToAllPeers发送数据包的速度不够快。



我正在尝试通过蓝牙连接发送文件。

我已经得到了这个工作感谢我以前的帖子,但这种方法不是内存效率高。

整个文件在发送之前被加载到内存中,这对> ~ 20mb的文件产生了问题(并使应用程序崩溃)。所以我想出了一种新方法,在特定时间只读取我需要的部分文件,从数据中创建数据包,发送它们并为每个8KB的文件块重复此过程。

因此,我创建了一个类方法来生成数据包,通知控制器数据包可用(通过协议),并对每个可用的数据包重复此过程。

下面是包生成器的代码:

+ (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];
}

然而,内存使用是相当大的。和我想的不一样

我有点卡住了,因为我不想限制蓝牙共享小于20MB的文件。

感谢您的帮助。

编辑:
我已经考虑了一段时间,并得出结论,这不是我的代码,导致内存分配问题,这是GameKit的堆栈发送数据包。

我认为我生成的数据包太多太快了,我认为GameKit发送它们的速度不够快。

所以我现在正在考虑一种方法来查看GameKit何时发送了一个数据包,并且只有在GameKit确认它已发送时才生成另一个数据包。

你的代码中有一个明显的内存管理问题:

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

通过这样做,循环中的任何自动释放对象将在每次循环迭代结束时有效地释放。

检查NSInputStream。有了它,你可以打开一个流,一次只读出一个字节缓冲区。

最新更新