【问题标题】:GameKit's sendDataToAllPeers isn't sending packets quick enoughGameKit 的 sendDataToAllPeers 发送数据包的速度不够快
【发布时间】:2011-04-23 15:35:09
【问题描述】:

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

感谢我的previous post,我已经完成了这项工作,但该方法的内存效率不高。

整个文件在发送之前已加载到内存中,这会为 > ~20 MB 的文件带来问题(并使应用程序崩溃)。所以我想出了一种新方法,只在特定时间读取我需要的部分文件,从数据中创建数据包,发送它们并为文件的每个 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 确认已发送后才生成另一个数据包。

【问题讨论】:

    标签: iphone objective-c memory-management memory-leaks bluetooth


    【解决方案1】:

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

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

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

    【讨论】:

    • 可悲的是,内存使用率很高。我不确定是什么分配了所有这些内存,这变得有点烦人。
    • @Jack 你释放你的实例变量/将你声明的属性设置为nil in -[file_packet dealloc]
    【解决方案2】:

    查看NSInputStream。有了它,您可以打开一个流并且一次只读取一个字节缓冲区。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      相关资源
      最近更新 更多