Saving/loading a 2D C array with NSKeyedArchiver - iphone

Malloc like this
int **terrain;
terrain = malloc(sizeof(int*) * mapSize.x);
for (int i = 0; i < mapSize.x; i++) {
terrain[i] = malloc(mapSize.y * sizeof(int));
}
Use it.
Convert to NSdata like this before saving
NSData *data=[NSData dataWithBytes:terrain length:(30*sizeof(int*) +30*30*sizeof(int) )];
[rootObject setValue:data forKey:#"terrain"];
[NSKeyedArchiver archiveRootObject: rootObject toFile: path];
loading into NSdata then converting back to int**
rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSData *data = [rootObject valueForKey:#"terrain"];
terrain =(int**) [data bytes];
With this code, is it saving the *int addresses then when I load the data it does not point to the correct data any more?
Or do I have a problem with the "endianness" as described in
Documentation
If it is the address issue, should i put a for loop when saving to convert *int to NSData then save all those and recreate the **int with another for loop/malloc?

I haven't tested this but I suspect that with the mallocs above there is no guarantee that you will have a continuous area of memory allocated.
what you could do is save the data separately for all mapSize.x array of bytes:
int **terrain;
terrain = malloc(sizeof(int*) * mapSize.x);
for (int i = 0; i < mapSize.x; i++) {
terrain[i] = malloc(mapSize.y * sizeof(int));
}
...
for (int j = 0; j < mapSize.x; j++)
{
NSData *data=[NSData dataWithBytes:terrain[j] length:(mapSize.y * sizeof(int))];
[rootObject setValue:data forKey:[NSString stringWithFormat:#"terrain%i", j]];
}
[rootObject setValue:mapSize.x forKey:#"terrain"];
[NSKeyedArchiver archiveRootObject:rootObject toFile:path];

I would convert the 2D array into NSArrays before archiving, because it will save you a lot of hassle.
NSMutableArray* terrainForArchiving = [NSMutableArray arrayWithCapacity:mapSize.x];
for(int col = 0; col < mapSize.x; ++col){
NSMutableArray* terrainCol = [NSMutableArray arrayWithCapacity:mapSize.y];
for(int row = 0; row < mapSize.y; ++row){
[terrainCol addObject:[NSNumber numberWithInt:terrain[col][row]]];
}
[terrainForArchiving addObject:terrainCol];
}
[NSKeyedArchiver archiveRootObject:terrainForArchiving];

Related

Create 1 million NSMutableArrays with unique names easily

After teaching myself (mostly from this website) I have finally been unable to find a solution to a problem.
I am trying to easily create 1 million NSMutableArrays with unique names. What I mean by easily is not having 'hard code' all of the individual arrays.
What I would like to do is something like this:
for (int i = 1; i <= 1000000; i++) {
NSString *arrayNumber = [NSString stringWithFormat:#"%d", i];
NSString *millionArrayNumber = #"millionArrayNumber";
NSString *arrayName = [millionArrayNumber stringByAppendingString:arrayNumber];
NSMutableArray *[NSString arrayName] = [NSMutableArray array];
}
I can understand why this doesn't work but I can't think of another way of doing it. I thought it might be possible to use something similar to:
[button setTag = 1];
If I change the code to:
for (int i = 1; i <= 1000000; i++) {
NSMutableArray *millionArray = [NSMutableArray array];
[millionArray setTag: i];
}
I would then use the tag to control the arrays as you can do with buttons. This doesn't work for arrays though.
I hope I haven't been ambiguous.
I'm not sure how to convert a string into literal code like you're doing, but I think it's possible.
However, you can always just kick 1 million arrays to an NSMutableDictionary and give each one your unique key name.
NSMutableDictionary *arrayStore = [NSMutableDictionary dictionary];
for (int i = 1; i <= 1000000; i++) {
NSString *arrayNumber = [NSString stringWithFormat:#"%d", i];
NSString *millionArrayNumber = #"millionArrayNumber";
NSString *arrayName = [millionArrayNumber stringByAppendingString:arrayNumber];
arrayStore[arrayName] = [NSMutableArray array];
}
And obviously to get whatever array you want later, you just use:
NSMutableArray *uniqueArray = arrayStore[arrayName];
Edit: Not sure if you want to keep the number as the unique key as mentioned in the comment below but if so, you can do it with this:
NSMutableDictionary *arrayStore = [NSMutableDictionary dictionary];
for (int i = 1; i <= 1000000; i++) {
arrayStore[#(i)] = [NSMutableArray array];
}
And access it with (for example, array number 100):
NSMutableArray *uniqueArray = arrayStore[#100];

hex a to binary

i am trying to convert my hex value to binary value , but i am facing little problem .
as i am new trying to learn my faults .
my code :
NSMutableString *str;
NSString *dd = #"192:168:1:2:0B:2:D:00";
NSCharacterSet *donotwant1 = [NSCharacterSet characterSetWithCharactersInString:#":""];
dd =[[dd componentsSeparatedByCharactersInSet:donotwant1] componentsJoinedByString:#" "];
NSMutableArray *array = [[dd componentsSeparatedByString:#" "] mutableCopy];
[array removeObjectAtIndex:0];
//NSLog(#"%#",array);
for (int j=0; j<[array count]; j++) {
NSScanner *scan = [NSScanner scannerWithString:[array objectAtIndex:j]];
unsigned int i=0;
if ([scan scanHexInt:&i]) {
// NSLog(#"numbner is %ustr", i);
}
NSInteger theNumber = i;
str = [NSMutableString string];
for(NSInteger numberCopy = theNumber; numberCopy > 0; numberCopy >>= 1) {
// Prepend "0" or "1", depending on the bit
[str insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
[array removeObjectAtIndex:j];
[array insertObject:str atIndex:j];
}
}
NSLog(#"Binary version: %#", array);
I'm getting
1,1100,11001111,1111,1111,11101111.....
in my code 0 values are eliminated . i want 8bits like(00000001,00001100.....) can any one tell me the reason
When the most significant bit is reached, your algorithm stops the conversion. Why not force the loop to always execute 8 times?
for (int numberCopy = theNumber, int i = 0; i < 8; numberCopy >>= 1, i++) {
// loop body here
}
By the way, here's a cleaner/shorter/simpler approach that doesn't involve highly superfluous copying and uses characters instead of string objects for hyper efficiency (just kidding, I'm all against micro-optimizations, but I feel like inserting an NSString before another one is unnecessary, especially if the number of bits is known and constant). This also assumes UTF-8 and exploits the fact that hexadecimal and binary representation have a very nice relationship, 16 being the 4th power of 2:
NSString *dd = #"01:0C:CF:0F:EF:AF:BD:00";
NSArray *bytes = [dd componentsSeparatedByString:#":"];
NSMutableArray *binaries = [NSMutableArray array];
NSString *lookup[256];
lookup['0'] = #"0000";
lookup['1'] = #"0001";
lookup['2'] = #"0010";
lookup['3'] = #"0011";
lookup['4'] = #"0100";
lookup['5'] = #"0101";
lookup['6'] = #"0110";
lookup['7'] = #"0111";
lookup['8'] = #"1000";
lookup['9'] = #"1001";
lookup['A'] = #"1010";
lookup['B'] = #"1011";
lookup['C'] = #"1100";
lookup['D'] = #"1101";
lookup['E'] = #"1110";
lookup['F'] = #"1111";
for (NSString *s in bytes) {
unichar n1 = [s characterAtIndex:0];
unichar n0 = [s characterAtIndex:1];
[binaries addObject:[lookup[n1] stringByAppendingString:lookup[n0]]];
}
NSLog(#"%#", binaries);

How to create byte array from NSData

Please any one guide me how to create bytes array from nsdata here is my code for createing nsdata
NSData* data = UIImagePNGRepresentation(img);
If you only want to read them, there's a really easy method :
unsigned char *bytes = [data bytes];
If you want to edit the data, there's a method on NSData that does this.
// Make your array to hold the bytes
NSUInteger length = [data length];
unsigned char *bytes = malloc( length * sizeof(unsigned char) );
// Get the data
[data getBytes:bytes length:length];
NB Don't forget - if you're copying the data, you also have to call free(bytes) at some point ;)
Here is fastest way (but pretty danger) to get array:
unsigned char *bytesArray = data.bytes;
NSUInteger lengthOfBytesArray = data.length;
before trying to get byte#100 you should check lengthOfBytesArray like:
if (lengthOfBytesArray > 100 + 1)
{
unsigned char byteWithOffset100 = bytesArray[100];
}
And another safe and more objc-like way:
- (NSArray*) arrayOfBytesFromData:(NSData*) data
{
if (data.length > 0)
{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:data.length];
NSUInteger i = 0;
for (i = 0; i < data.length; i++)
{
unsigned char byteFromArray = data.bytes[i];
[array addObject:[NSValue valueWithBytes:&byteFromArray
objCType:#encode(unsigned char)]];
}
return [NSArray arrayWithArray:array];
}
return nil;
}

Retrieve NSData to Hex by length

I got a NSData that contain bytes like <00350029 0033> with length 6, is there any correct way to split the bytes to array somehow like (00, 35, 00, 29, 00, 33) ?
NSData *data = ...;
NSMutableArray *bytes = [NSMutableArray array];
for (NSUInteger i = 0; i < [data length]; i++) {
unsigned char byte;
[data getBytes:&byte range:NSMakeRange(i, 1)];
[bytes addObject:[NSString stringWithFormat:#"%x", byte]];
}
NSLog(#"%#", bytes);
(Assuming you want the bytes as a hex string representation, as in your example. Otherwise, use NSNumber.)
You could use the NSData method
- (void)getBytes:(void *)buffer range:(NSRange)range
to get the bytes in a given range (after having allocated the right amount of memory, using malloc), then use
+ (id)dataWithBytes:(const void *)bytes length:(NSUInteger)length
to create new small (1 byte long) data objects which you then put into an array. However if you just retrieve the pointer to the bytes themselves (using [data bytes]), that gives you a pointer (kind of an array in the C sense, not an NSArray, but could also be used and far more efficient).
static NSString* HexStringFromNSData(NSData* data) {
NSUInteger n = data.length;
NSMutableString* s = [NSMutableString stringWithCapacity:(2 * n)];
const unsigned char* ptr = [data bytes];
for(NSUInteger i = 0; i < n; i++, ptr++) {
[s appendFormat:#"%02x", (long)*ptr];
}
return [NSString stringWithString:s];
}

Is this a valid way to build and send NSData through GameKit?

Its y first time trying to use NSData and Gamekit. So was wondering am i packing the data properly?
- (void)sendNetworkPacket:(GKSession *)session packetID:(int)packetID
reliable:(BOOL)howtosend
{
// the packet we'll send is resued
static unsigned char networkPacket[kMaxTankPacketSize];
const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our
header
int *pIntData = (int *)&networkPacket[0];
// header info
pIntData[0] = gamePacketNumber++;
pIntData[1] = packetID;
int theLength = 2 * sizeof(int);
for (int i=0; i<([theHands.player1Hand count]); i++)
{
pIntData[2+i] = [[theHands.player1Hand objectAtIndex:i] intValue];
theLenght += sizeof(int);
}
NSData *packet = [NSData dataWithBytes: networkPacket length: theLength];
[session sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId]
withDataMode:GKSendDataReliable error:nil];
}
Will the data I put into NSData *packet be valid?
Many Thanks,
-Code
You create the NSData correctly, and it will contain what you expect. But this is rather more complicated than necessary. The following will do too:
enum { kHeaderLength = 2 };
NSMutableData *packet = [NSMutableData dataWithLength: (kHeaderLength + [theHands.player1Hand count]) * sizeof( int )];
int *pIntData = (int *)[packet mutableBytes];
*pIntData++ = gamePacketNumber++;
*pIntData++ = packetID;
for (id thing in theHands.player1Hand) {
*pIntData++ = [thing intValue];
}
[session sendData: packet toPeers: [NSArray arrayWithObject: gamePeerId] withDataMode: GKSendDataReliable error: NULL];
This will have some advantages:
The packet data will not be copied to the NSData object, it will be created directly in there.
You don’t have to depend on a maximum packet size. You used a constant, which is good since you could change that in one place if bigger packets are required some time. But this is not really needed.
Your version is not thread safe since it depends on the static buffer. This might be fine, since not every method has to be thread-safe. But this is something one has to look out for.
Using fast enumeration also helps keeping the overhead down and is more readable.