Чтобы добавить:
То, что вы должны здесь сделать, - это создать подкласс NSObject для представления вашего пакета, а затем принять NSCoding для сериализации его в NSData желаемым способом.Выполнение этого со структурой ничего не покупает, а усложняет.Это также хрупко, так как упаковка структуры в NSData не учитывает такие вещи, как endian-ness и т. Д.
Сложная часть процесса пакетирования с использованием NSCoding заключается в том, что вы на самом деле не знаете, что такое издержкипроцесса кодирования, поэтому быть настолько большим, насколько это возможно, но все же при максимальном размере пакета сложно, *
Я представляю это без тестирования или гарантии, но если вы хотите достойный старт на этом подходеэто может быть это.Будьте предупреждены, я не проверял, были ли мои произвольные 100 байтов для служебных данных реалистичными.Вам придется немного поиграть с числами.
Packet.h:
@interface Packet : NSObject <NSCoding>
{
NSString* fileName;
NSInteger fileType;
NSUInteger totalPackets;
NSUInteger packetIndex;
NSData* packetContents;
}
@property (readonly, copy) NSString* fileName;
@property (readonly, assign) NSInteger fileType;
@property (readonly, assign) NSUInteger totalPackets;
@property (readonly, assign) NSUInteger packetIndex;
@property (readonly, retain) NSData* packetContents;
+ (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents;
@end
Packet.m:
#import "Packet.h"
@interface Packet ()
@property (readwrite, assign) NSUInteger totalPackets;
@property (readwrite, retain) NSData* packetContents;
@end
@implementation Packet
- (id)initWithFileName: (NSString*)pFileName ofType: (NSInteger)pFileType index: (NSUInteger)pPacketIndex
{
if (self = [super init])
{
fileName = [pFileName copy];
fileType = pFileType;
packetIndex = pPacketIndex;
totalPackets = NSUIntegerMax;
packetContents = [[NSData alloc] init];
}
return self;
}
- (void)dealloc
{
[fileName release];
[packetContents release];
[super dealloc];
}
@synthesize fileName;
@synthesize fileType;
@synthesize totalPackets;
@synthesize packetIndex;
@synthesize packetContents;
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject: self.fileName forKey: @"fileName"];
[aCoder encodeInt64: self.fileType forKey:@"fileType"];
[aCoder encodeInt64: self.totalPackets forKey:@"totalPackets"];
[aCoder encodeInt64: self.packetIndex forKey:@"packetIndex"];
[aCoder encodeObject: self.packetContents forKey:@"totalPackets"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init])
{
fileName = [[aDecoder decodeObjectForKey: @"fileName"] copy];
fileType = [aDecoder decodeInt64ForKey:@"fileType"];
totalPackets = [aDecoder decodeInt64ForKey:@"totalPackets"];
packetIndex = [aDecoder decodeInt64ForKey:@"packetIndex"];
packetContents = [[aDecoder decodeObjectForKey:@"totalPackets"] retain];
}
return self;
}
+ (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents
{
const NSUInteger quanta = 8192;
Packet* first = [[[Packet alloc] initWithFileName:name ofType:type index: 0] autorelease];
// Find out how big the NON-packet payload is...
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[first encodeWithCoder: coder];
[coder finishEncoding];
const NSUInteger nonPayloadSize = [data length];
NSMutableArray* packets = [NSMutableArray array];
NSUInteger bytesArchived = 0;
while (bytesArchived < [fileContents length])
{
Packet* nextPacket = [[[Packet alloc] initWithFileName: name ofType: type index: packets.count] autorelease];
NSRange subRange = NSMakeRange(bytesArchived, MIN(quanta - nonPayloadSize - 100, fileContents.length - bytesArchived));
NSData* payload = [fileContents subdataWithRange: subRange];
nextPacket.packetContents = payload;
bytesArchived += [payload length];
[packets addObject: nextPacket];
}
for (Packet* packet in packets)
{
packet.totalPackets = packets.count;
}
return packets;
}
- (NSData*)dataForSending
{
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[self encodeWithCoder: coder];
[coder finishEncoding];
return [NSData dataWithData:data];
}
+ (Packet*)packetObjectFromRxdData:(NSData*)data
{
NSKeyedUnarchiver* decoder = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
return [[[Packet alloc] initWithCoder:decoder] autorelease];
}
@end
Повторная сборка оригиналафайл из этих пакетов можно сделать, используя тот же подход, что и его разбиение ... Перебирайте пакеты, копируя из отдельных полезных данных пакета NSDatas в большой NSMutableData.
В заключение я вынужден сказать, чточто когда вы обнаруживаете, что делаете что-то подобное, сводящееся к реализации примитивного стека TCP, обычно пора остановиться и спросить, нет ли лучшего способа сделать это.Иными словами, если бы GameKit был лучшим способом передачи файлов между устройствами по Bluetooth, можно было бы ожидать, что у API был бы метод для этого, но вместо этого у него было бы ограничение в 8 КБ.
Я небыть намеренно загадочным - я не знаю, какой API подойдет для вашей ситуации, но упражнение по приготовлению этого класса Packet заставило меня задуматься: «Должен быть лучший путь».
Надеюсь, этопомогает.