How to send int between 32bit and 64bit processors iOS - ios

Pretty much the title, I send an int in a struct using Gamekit and on the receiving end the other device gets it.
Between 64bit cpus (iPhone 5S and over) the number is received fine. But when a iPhone 5 gets it (32bit cpu) the int is received as 0. Whats the correct way?
I've tried sending as NSInteger and the results are the same.
I have to add I have this issue with u_int_32t:
When devices connect, each device trades random numbers. These numbers determine which player starts, and I'm using u_int_32t for this, however, 32bit cpus still receive 0. For example:
I declare
uint32_t _ourRandomNumber;
Then, _ourRandomNumber = arc4random();
And then the numbers are sent, in a struct like this.
typedef struct {
Message message;
uint32_t randomNumber;
} MessageRandomNumber;
Using a method like this:
- (void)sendRandomNumber{
MessageRandomNumber message;
message.message.messageType = kMessageTypeRandomNumber;
message.randomNumber = _ourRandomNumber;
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageRandomNumber)];
[self sendData:data];
}
When the 32 bit cpu receives it then in the receiving method:
Message *message = (Message*)[data bytes];
if (message->messageType == kMessageTypeRandomNumber) {
MessageRandomNumber *messageRandomNumber = (MessageRandomNumber*)[data bytes];
NSLog(#"Received random number:%d", messageRandomNumber->randomNumber);
The NSLog shows: Received random number:0

NSInteger is going to be 64-bit on a 64-bit platform and 32-bit on a 32-bit platform. If you don't care about 64-bit precision, you could always use an int32_t (or a u_int32_t if you want unsigned) type to explicitly just use a 32-bit value. It is generally wise to be explicit about data lengths when sending values between devices, which is what these types exist for (there's int8_t, int16_t, int32_t, and int64_t and their unsigned counterparts).
It's also worth mentioning that you need to be concerned about the byte order of the values (assuming larger values than int8_t and u_int8_t) when sending values to arbitrary hardware. If you're only working with iOS devices this isn't going to be an issue, however.

Related

In Core Data which attribute type (Integer 16 / 32 / 64) should I use to store small numbers? [duplicate]

I want to keep NSUInteger into my core data and I don't know which type should I use (integer 16, 32, 64) to suit the space needed.
From my understanding:
Integer 16 can have minimum value of -32,768 to 32,767
Integer 32 can have minimum value of -2,147,483,648 to 2,147,483,647
Integer 64 can have minimum value of -very large to very large
and NSUInteger is type def of unsigned long which equal to unsigned int (Types in objective-c on iPhone)
so If I convert my NSUInteger to NSNumber with numberWithUnsignedInteger: and save it as NSNumber(Integer 32) I could retrieve my data back safely right?
Do you really need the entire range of an NSUInteger? On iOS that's an unsigned 32 bit value, which can get very large. It will find into a signed 64 bit.
But you probably don't need that much precision anyway. The maximum for a uint32_t is UINT32_MAX which is 4,294,967,295 (4 billion). If you increment once a second, it'll take you more than 136 years to reach that value. Your user's iPhone won't be around by then... :)
If at all possible, when writing data to disk or across a network, it's best to be explicit about the size of value. Instead of using NSUInteger as the datatype, use uint16_t, uint32_t, or uint64_t depending on the range you need. This then naturally translates to Integer 16, 32, and 64 in Core Data.
To understand why, consider this scenario:
You opt to use Integer 64 type to store your value.
On a 64-bit iOS device (eg iPhone 6) it stores the value 5,000,000,000.
On a 32-bit iOS device this value is fetched from the store into an NSUInteger (using NSNumber's unsignedIntegerValue).
Now because NSUInteger is only 32-bits on the 32-bit device, the number is no longer 5,000,000,000 because there aren't enough bits to represent 5 billion. If you had swapped the NUInteger in step 3 for uint64_t then the value would still be 5 billion.
If you absolutely must use NSUInteger, then you'll just need to be wary about the issues described above and code defensively for it.
As far as storing unsigned values into the seemingly signed Core Data types, you can safely store them and retrieve them:
NSManagedObject *object = // create object
object.valueNumber = #(4000000000); // Store 4 billion in an Integer 32 Core Data type
[managedObjectContext save:NULL] // Save value to store
// Later on
NSManagedObject *object = // fetch object from store
uint32_t value = object.valueNumber.unsignedIntegerValue; // value will be 4 billion

Handling 64 bit integers on a 32 bit iPhone

I would like to handle 64 bit unsigned integers on a iPhone 4s (which of course has a 32 bit ARM 6 processor).
When trying to work with 64 bit unsigned integers, e.g. Twitter IDs, I have the following problem:
// Array holding the 64 bit integer IDs of the Tweets in a timeline:
NSArray *Ids =[timelineData valueForKeyPath:#"id"];
// I would like to get the minimum of these IDs:
NSUInteger minId = (NSUInteger) Ids.lastObject;
The array Ids contains the following numbers (= Tweet Ids):
491621469123018752,
491621468917477377,
491621465544851456,
491621445655867393
However, minId returns the incorrect value of 399999248 (instead of 491621445655867393)
How can I find the minimum or the last object in an Array of 64 bit integers on an iPhone 4s?
You need to use a type that is always 64 bit instead of NSUInteger. You can use uint64_t or unsigned long long. You also need to get the integer value out of the NSNumber (arrays can't store C types). to do this you need to call
uint64_t minID = [Ids.lastObject longLongValue];
Edit
Changed to use uint64_t in example code as it has been correctly pointed out this shows your intent better.

Xamarin- Copy Data From IntPtr of NSDATA class.Bytes property into uint16 var

I am creating a blutooth app in Xamarin.ios platform. I am having issues collating data which comes from the peripheral that my app is connected. I have below objective c code but i am having hard time converting it to the C#. As i am not sure how to spilt the array of bytes in c#. Any advice how to correctly receive the data from the device.I thought of using Marshal class but not sure if it does the same thing as it does on iOS operating system level.
this is objective c code which works fine on iOS operating system level
UInt16 cValue;
[characteristic.value getBytes:&cValue length:2];
As you can see it calls getBytes method of NSDATA class From Apple API which does the trick but I could not find something similar in NSDATA class From Xamarin.ios API.
And this is what I think of doing it in C#:
byte []destination=new byte[16]();
Marshal.Copy(characteristic.Value.Bytes,destination,2, Not Sure about length);
Here's the marshal method that I used.
http://msdn.microsoft.com/en-us/library/vstudio/ms146631
Last thing, I am not sure about the byte[16] i just assumed that because Uint16 in objective c is 8 bit unsigned integer.
First of all, UInt16 is a 16-bit unsigned integer. byte[16] is a 16-byte array of 8-bit unsigned integers.
You will want a byte[2] to store the Uint16.
byte[] bytes = new byte[characteristic.Value.Length];
Marshal.Copy(characteristic.Value.Bytes, bytes, 0, Convert.ToInt32(characteristic.value.Length));
To finally convert to a ushort that is the equivalent to an Objective-C UInt16, you can use
ushort value = (ushort)(bytes[0] | (bytes[1] << 8))
Update
For a little-endian uint (objc UInt32), the conversion would look like this
uint value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);

objective c implicit conversion loses integer precision 'NSUInteger'

Following a tutorial on treehouse, I'm see this popular Object-C warning message in XCode.
My button function
- (IBAction)buttonPressed:(UIButton *)sender {
NSUInteger index = arc4random_uniform(predictionArray.count);
self.predictionLabel.text = [predictionArray objectAtIndex:index];
}
I see it on the NSUInteger line, I've few a few of the similar stackoverflows and they seem to talk about 32bit vs 64bit numbers and type casting, but not sure how to do that here?
My predictionArray
- (void)viewDidLoad
{
[super viewDidLoad];
predictionArray = [[NSArray alloc] initWithObjects:
#"It is certain", #"It is decidely so", #"All signs say YES", #"The stars are not aligned",
#"My reply is no",
#"It is doubtful",
#"Better not tell you now",
#"Concentrate and ask again",
#"Unable to answer now", nil];
// Do any additional setup after loading the view, typically from a nib.
}
You can safely suppress the warning with a cast.
NSUInteger index = arc4random_uniform((uint32_t) predictionArray.count);
It's not always safe to suppress warnings, so don't go casting things to get rid of the warnings until you figure out whether the operation is safe.
What's going on here is that NSUInteger is, on your platform, a typedef for a 64-bit integer type. It's not always 64 bits, just on some platforms. The compiler is warning you that some of those bits are getting thrown away. If you know that these bits are unimportant, you can just use a cast.
In this case, the result is that index will always be under 232-1. If it's even remotely possible for predictionArray to contain 232 or more elements, then your program has an error and you'll have to construct a 64-bit version of arc4random_uniform(). You can ensure this with the following code:
assert(predictionArray.count <= (uint32_t) -1);
As per my comment, arc4random_uniform() takes in, and returns, a u_int32_t, an unsigned integer that is always 32 bits, regardless of target architecture. However, predictionArray.count returns an NSUInteger, which is typedefd differently for 32-bit and 64-bit systems; it's 32 bits (unsigned int) on a 32-bit system, and 64-bits (unsigned long) on a 64-bit system. If you're running on a 64-bit system, passing in a 64-bit NSUInteger to a function expecting a 32-bit integer will cause the compiler to complain that you're throwing away bits.

How do I detect a dual core CPU on iOS?

My app uses an NSOperationQueue to cache thumbnail images in a background thread. On the iPad2 I can push the concurrent task count limit up to 5 or 6, but on single core devices like the iPad 1 this brings the UI to a grinding halt.
So, I'd like to detect a dual core device (currently only iPad 2) and adapt the concurrent limit appropriately. I know I'm not supposed to check model numbers, rather device features. So what device feature should I be looking for that would tell me whether the cpu is dual core?
Method 1
[[NSProcessInfo processInfo] activeProcessorCount];
NSProcessInfo also has a processorCount property. Learn the difference here.
Method 2
#include <mach/mach_host.h>
unsigned int countCores()
{
host_basic_info_data_t hostInfo;
mach_msg_type_number_t infoCount;
infoCount = HOST_BASIC_INFO_COUNT;
host_info( mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount ) ;
return (unsigned int)(hostInfo.max_cpus);
}
Method 3
#include <sys/sysctl.h>
unsigned int countCores()
{
size_t len;
unsigned int ncpu;
len = sizeof(ncpu);
sysctlbyname ("hw.ncpu",&ncpu,&len,NULL,0);
return ncpu;
}
Just use:
[[NSProcessInfo processInfo] processorCount]
I guess this needs a separate answer rather than a comment:
I wonder what does the number of cores means now that apple brought more asymmetric processing with A10 fusion? Do we have 2.2 cores or 4 cores? apple neglected to make activeProcessorCount float to account for it's fractal nature. note it was like so even before fusion cause they likely had thermal throttling back then. They need either fix overcomittal of nsoperationqueue or come up with a float equivalent for activeProcessorCount and deprecate the activeProcessorCount in its current form that is losing its utility in the face of recent hw advancements
So the faster the Moore's law falls into oblivion or receives a shiny new constant
the more meaningless core counting becomes. Unless you are writing some sort
of a Geek Bench 42, multicore score edition.
Living in the late 2016, to address the underlying issue you are facing rather than hacking through with max concurrent operation prop I assume
you have adjusted the QoS for the NSOperationQueue to .Background?
Me thinks this is a cleaner way to solve your problem with modern
ios sdk then counting 'em cores using miles of rope courtesy of albertamg
Also please take a look at
NSProcessInfoThermalStateDidChangeNotification (macos) and NSProcessInfo.lowPowerModeEnabled (ios)
(I guess an alternative to observing NSProcessInfoThermalStateDidChangeNotification
is to KVo on activeProcessorCount new value)
if you start to account for those new realities, the magic constants adjustments
for multiplying core count would get interesting very fast...
and rot as the new hardware rolls out of cupertino.
And it will be just about as easy to get it right on the current
zoo of Apple hw as to get socket-level networking working correctly:
doable, but by select few in Cupetino with iSteve shadow
looming over the shoulder checking quality ;-)
In Swift you can detect / print the number of active processors with the following code:
let processInfo = ProcessInfo()
print(processInfo.activeProcessorCount)
This code does not need any extra header files or frameworks and works completely natively.
Among other things, you can get that information through a system call...
NSDictionary dictionaryWithObjectsAndKeys:
[self machineType],#"MachineType",
[self humanMachineType],#"HumanMachineType",
[self powerPCTypeString],#"ProcessorType",
[NSNumber numberWithLong:
[self processorClockSpeed]],
#"ProcessorClockSpeed",
[NSNumber numberWithLong:
[self processorClockSpeedInMHz]],
#"ProcessorClockSpeedInMHz",
[NSNumber numberWithInt:[self countProcessors]],
#"CountProcessors",
[self computerName],#"ComputerName",
[self computerSerialNumber],#"ComputerSerialNumber",
[self operatingSystemString],#"OperatingSystem",
[self systemVersionString],#"SystemVersion",
nil];
Here's the reference...
http://cocoadev.com/HowToGetHardwareAndNetworkInfo
I guess:
sysctl(HW_NCPU)
or
sysctlbyname("hw.ncpu", NULL, &size, NULL, 0);
should work.
you can modify code from: Detect the specific iPhone/iPod touch model
Swift 5
To obtain logical cores count use this snippet:
let logicalCoresCount = ProcessInfo.processInfo.processorCount
To obtain physical cores count use below one:
func physicalCoresCount() -> UInt {
var size: size_t = MemoryLayout<UInt>.size
var coresCount: UInt = 0
sysctlbyname("hw.physicalcpu", &coresCount, &size, nil, 0)
return coresCount
}

Resources