Create a stopwatch with zeros before numbers [duplicate] - ios

I have the following variable:
NSNumber *consumption = [dict objectForKey:#"con"];
Which returns 42. How can I pad this number to 10 digits on the left, leading with zeros. The output should look as,
0000000042
or if it were 420,
0000000420

NSString *paddedStr = [NSString stringWithFormat:#"%010d", 42];
EDIT: It's C style formatting. %nd means the width is at least n. So if the integer is 2 digit long, then you will have length 3 string (when %3d is used). By default the left empty spaces are filled by space. %0nd (0 between % and n) means 0 is used for padding instead of space. Here n is the total length. If the integer is less than n digits then left padding is used.

The Objective-C way,
NSNumberFormatter * numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[numberFormatter setPaddingPosition:NSNumberFormatterPadBeforePrefix];
[numberFormatter setPaddingCharacter:#"0"];
[numberFormatter setMinimumIntegerDigits:10];
NSNumber * number = [NSNumber numberWithInt:42];
NSString * theString = [numberFormatter stringFromNumber:number];
NSLog(#"%#", theString);
The C way is faster though.

You can't in the NSNumber itself. If you're creating a string from the number or using NSLog(), simply use the appropriate format, e.g.
NSLog(#"%010d", [consumption intValue]);

You can do pretty much any number formatting you would ever want with NSNumberFormatter. In this case I think you would want to use the setFormatWidth: and setPaddingCharacter: functions.

with variable num_digits
NSString* format =[NSString stringWithFormat:#"%%0%zdzd", num_digits];
NSString *theString = [NSString stringWithFormat:format, 42];

E.g. Fill the rest with zeros, 5 digits:
NSInteger someValue = 10;
[NSString stringWithFormat:#"%05ld", someValue];
Equivalent of .02f for float number when you need only 2 digits after the dot.
So there you have 0 = fill with zeros, 5 = the number of digits and type.

Solution for Swift 3
let x = 1078.1243
let numFormatter = NumberFormatter()
numFormatter.minimumFractionDigits = 1 // for float
numFormatter.maximumFractionDigits = 1 // for float
numFormatter.minimumIntegerDigits = 10 // how many digits do want before decimal
numFormatter.paddingPosition = .beforePrefix
numFormatter.paddingCharacter = "0"
let s = numFormatter.string(from: NSNumber(floatLiteral: x))!
OUTPUT
"0000001078.1"

Related

swift3 Date to Data, Data to Date convert

I am working on changing the code created in objective c to swift3.
I want to change the code below to the swift3 code created with objective c.
Objective c NSDate to NSData code :
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSDayCalendarUnit |NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]];
NSInteger year = components.year;
NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];
int month = components.month;
int day = components.day;
int hour = components.hour;
int min = components.minute;
int second = components.second;
char bytes[7];
bytes[0] = year1;
bytes[1] = year2;
bytes[2] = month;
bytes[3] = day;
bytes[4] = hour;
bytes[5] = min;
bytes[6] = second;
NSData *data = [[NSData alloc] initWithBytes:&bytes length:sizeof(bytes)];
Objective c NSData to NSDate code :
NSData *date = [[NSData alloc] initWithData:characteristic.value];
int year = *(int *)[[date subdataWithRange:NSMakeRange(0, 2)] bytes];
int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];
int day = *(int *)[[date subdataWithRange:NSMakeRange(3, 1)] bytes];
int hour = *(int *)[[date subdataWithRange:NSMakeRange(4, 1)] bytes];
int minutes = *(int *)[[date subdataWithRange:NSMakeRange(5, 1)] bytes];
int seconds = *(int *)[[date subdataWithRange:NSMakeRange(6, 1)] bytes];
NSLog(#"year %d month %d day %d hour %d minutes %d second %d", year, month, day, hour, minutes, seconds); //year 2017 month 7 day 13 hour 16 minutes 8 second 2
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:year];
[components setMonth:month];
[components setDay:day];
[components setHour:hour];
[components setMinute:minutes];
[components setSecond:seconds];
NSCalendar *calendar = [NSCalendar currentCalendar];
self.time = [calendar dateFromComponents:components];
Swift Date to Data code :
let cal = Calendar(identifier: .gregorian)
var comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: Date())
var year = comp.year
let yearData:Data = Data(bytes: &year, count: MemoryLayout.size(ofValue: year))
let year1:Data = yearData.subdata(in: 0..<1)
let year2:Data = yearData.subdata(in: 1..<2)
let settingArray = [UInt8]([
UInt8(year1[0])
, UInt8(year2[0])
, UInt8(comp.month!)
, UInt8(comp.day!)
, UInt8(comp.hour!)
, UInt8(comp.minute!)
, UInt8(comp.second!)
])
let settingData:Data = Data(bytes: settingArray, count: MemoryLayout.size(ofValue: settingArray))
Swift Data to Date code :
var yearVal:UInt8 = 0
let year = characteristic.value?.subdata(in: 0..<2)
year?.copyBytes(to: &yearVal, count: MemoryLayout.size(ofValue: year))
var month = characteristic.value?.subdata(in: 2..<3)
var day = characteristic.value?.subdata(in: 3..<4)
var hour = characteristic.value?.subdata(in: 4..<5)
var minutes = characteristic.value?.subdata(in: 5..<6)
var seconds = characteristic.value?.subdata(in: 6..<7)
print("year = \(yearVal), month = \(Int((month?[0])!)), day = \(Int((day?[0])!)), hour = \(Int((hour?[0])!)), minutes = \(Int((minutes?[0])!)), seconds = \(Int((seconds?[0])!))") // year = 225, month = 7, day = 13, hour = 15, minutes = 56, seconds = 56
When I modify the let year = characteristic.value?.subdata(in: 0..<2) part, the conversion value should be 2017. However, only 225 values are output. I do not know how to solve this part.
Please help me.
You are very lucky your Objective-C code works as you are reading unassigned memory and ignoring endian issues.
Consider the line:
int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];
Here you are taking a pointer to a single byte, casting it to a pointer to 4 bytes (the size on an int), and then reading 4 bytes and storing them in month. By luck the extra three bytes you read happen to be zero.
Then there is the endian issue, different cpu architectures store multi-byte values in different orders in memory. A little-endian architecture stores the least significant byte first, a big-endian one the most significant.
E.g. the 4-byte integer 0xDEADBEEF is stored as the byte sequence EF, BE, AD, DE on a little-endian machine and as DE, AD, BE, EF on a big-endian one. What this means in terms of your month value above is if the byte is 06 then you might get back the integer 0x06000000 when you read those 4 bytes (and only if those extra bytes are zeroes).
For the month case you could load the byte and then convert to an integer:
int month = (int *)(*(Byte *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes]);
When converting the year to two bytes you go through the long winded process:
NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];
This converts an integer to an NSData, makes to more NSData values containing 1 byte each, and then loads 4 bytes for each - the same issue as above, but in this case as you will only be storing 1 byte in your bytes array it doesn't matter if the extra bytes are garbage.
The process is convoluted, you would be better off sticking with integer operations to obtain the two values. You can obtain the individual bytes using division and remainder operations, or bit-wise shift and mask operations.
E.g. using decimal first to demonstrate:
int year = 2017;
int firstDigit = year % 10; // the remainder of year / 10 => 7
int secondDigit = (year / 10) % 10; // 1
int thirdDigit = (year / 100) % 10; // 0
int fourthDigit = (year / 1000) % 10; // 2
To extract the bytes just change the divisor:
int year = 2017; // = 0x7E1
int loByte = year % 256; // = 0xE1
int hiByte = (year / 256) % 256; // = 0x7
Finally you can use bit-wise shift and masking:
int year = 2017; // = 0x7E1
int loByte = year & 0xFF; // = 0xE1
int hiByte = (year >> 8) & 0xFF; // = 0x7
Using bit-wise operations makes the byte splitting more obvious, but divide and remainder achieve the same result.
What does all this mean in terms of your Objective-C code? Well the second of your two methods can be written:
+ (NSDate *) dataToDate:(NSData *)data
{
NSDateComponents *components = [[NSDateComponents alloc] init];
const Byte *bytes = data.bytes;
components.year = (NSInteger)bytes[0] | ((NSInteger)bytes[1] << 8); // reassemble 2-byte value
components.month = (NSInteger)bytes[2];
components.day = (NSInteger)bytes[3];
components.hour = (NSInteger)bytes[4];
components.minute = (NSInteger)bytes[5];
components.second = (NSInteger)bytes[6];
NSCalendar *calendar = [NSCalendar currentCalendar];
return[calendar dateFromComponents:components];
}
This is a lot less complex, doesn't read random memory, and is easier to convert to Swift.
Following the same approach here is your first method in Swift:
func toData(_ date : Date) -> Data
{
let cal = Calendar(identifier: .gregorian)
let comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: date)
let year = comp.year!
let yearLo = UInt8(year & 0xFF) // mask to avoid overflow error on conversion to UInt8
let yearHi = UInt8(year >> 8)
let settingArray = [UInt8]([
yearLo
, yearHi
, UInt8(comp.month!)
, UInt8(comp.day!)
, UInt8(comp.hour!)
, UInt8(comp.minute!)
, UInt8(comp.second!)
])
return Data(bytes: settingArray)
}
Finally, you can index the Data type in Swift lust like an array, so the above Objective-C line:
components.month = (NSInteger)bytes[2];
where bytes came from calling NSData's bytes can be written directly in Swift as:
components.month = Int(data[2])
where data is the Data value.
The above approach doesn't answer the issue you actually had, because it avoids messing with splitting data values into bits and trying to extra values from them - just index the byte and convert with a cast.
The rest of the code you need is left as an excercise!
HTH
you are fetching year value as UInt8 which only have range of 0-255 so use UInt32
var yearVal: UInt32 = 0
(year as! NSData).getBytes(&yearVal, length: MemoryLayout.size(ofValue: year))

CGFloat to NSString with decimal only if there is fractional part

Not sure how to word the title correctly... but what I am wondering is if there is some clever format specifier that will take the number 4.5 and give me #"4.5" but also take the number 2 and give me #"2".
Using the %.1f specifier gives me #"4.5" but also #"2.0". I am trying to get rid of the ".0" bit.
Does such a beast exist, or am I going to have to do some math on this? FWIW, I am trying to iterate over an array of values ranging from 0 to 5 increasing in half-steps, so 0, 0.5, 1, 1.5, ..., 4.5, 5
Cheers!
NSNumberFormatter is a good choice here. You can configure it to not show the fractional digits if the number is an integer. For example:
NSArray *numbers = #[#0, #0.5, #1.0, #1.5, #2.0, #2.5];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.alwaysShowsDecimalSeparator = NO;
numberFormatter.minimumFractionDigits = 0;
numberFormatter.maximumFractionDigits = 1;
numberFormatter.minimumIntegerDigits = 1;
for (NSNumber *number in numbers) {
NSLog(#"%#", [numberFormatter stringFromNumber:number]);
}
Output:
>> 0
>> 0.5
>> 1
>> 1.5
>> 2
>> 2.5
This is even easier (Swift):
let num1: Double = 5
let num2: Double = 5.52
let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = .DecimalStyle
print(numberFormatter.stringFromNumber(NSNumber(double: num1)))
print(numberFormatter.stringFromNumber(NSNumber(double: num2)))
This will print 5 and then 5.52.

How can I sum 2 positive and 1 negative float issue

I have some issue when calculating 3 CGFloats
I have: -34.522 + 39.049 + 0.2889 = ios gives me 73
but it should give me more like aproximative to an normal calculator values like = 4.81
CGFloat x = (46.2076 * -34.522) + (60.3827 * 39.049) + (2.028 * 0.2889);
NSLog(#"d %f",x); ->> 763.291199
CGFloat t = -34.522 + 39.049 + 0.2889;
NSLog(#"%f",t);
I'm not 100% sure if this is what you're asking, but if you only want 2 digits of precision, you have to specify this. It's easy to do via format specifier by using %.2f where 2 is the number of digits after the decimal place to be shown.
CGFloat x = (46.2076 * -34.522) + (60.3827 * 39.049) + (2.028 * 0.2889);
NSLog(#"d %.2f",x);
Alternatively, this can also be done with NSNumberFormatter.
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setPositiveFormat:#"#.##"];
NSString *output = [formatter stringFromNumber:#(x)];
NSLog(#"Out: %#",output);

Hashing the device id into a 64 bit (or greater) then convert that into base-31 [iOS]

I am having trouble hashing my device's id into a 64 bit (or greater) representation and then converting that into a base-31 representation. Any one have any tips or guidance? I have been looking online and can't seem to find much.
Each base-31 digit should then be represented by the this list: 2 3 4 5 6 7 8 9 A B C D E F G H J K M N P Q R S T U V W X Y Z
What I've tried:
NSString *myID = [[[UIDevice currentDevice] identifierForVendor]UUIDString];
NSLog(#"Non Hash: %#", myID); //Logs the 36 character string
myID = [NSString stringWithFormat:#"%lu",(unsigned long)[myID hash]]; // Changed thanks to rokjarc
NSLog(#"Hash: %#", myID); //Logs same 36 character string
//Logs 36 character string
NSLog(#"UUIDString: %#", [[[UIDevice currentDevice] identifierForVendor] UUIDString]);
//Logs out a 10 character numeric value
NSLog(#"Hash: %lu", (unsigned long)[[[[UIDevice currentDevice] identifierForVendor] UUIDString] hash]);
//Logs out a 2 character numeric value
NSLog(#"LongLong: %lld", [[[[UIDevice currentDevice] identifierForVendor] UUIDString] longLongValue]);
[[[UIDevice currentDevice] identifierForVendor]UUIDString] returns a UUID which is comprised of 32 hex characters which is 128 bits. 12 base31 characters can only represent 63 bits. Thus the entire UUID can not be represented.
Best bet is to run the UUID through SHA (which seems to be what [myID hash] does) and convert 63 of the bits of that into 12 base31 characters.
The reason for the hash function (SHA) is to remove any pattern in the UUID, each bit in the result of SHA is equally likely to be a 1 or 0.
Notes:
31^12 = 7.87E17 and 2^64 = 1.84E19
thus a 64 bit number can not be represented in 12 base 31 characters. 63 bit can however.
Base32 is a lot simpler than base31 for values larger than 64 bits.
Here is a code sample that creates a string of base31 characters from a 64-bit integer:
uint64_t uid = 14467240737094581;
NSString *baseCharacters = #"23456789ABCDEFGHJKMNPQRSTUVWXYZ";
NSUInteger base = baseCharacters.length;
NSMutableString *baseString = [NSMutableString new];
while (baseString.length < 12) {
uint64_t remainder = uid % base;
uid /= base;
NSString *baseCharacter = [baseCharacters substringWithRange:NSMakeRange(remainder, 1)];
[baseString insertString:baseCharacter atIndex:0];
}
NSLog(#"baseString: %#", baseString);
NSLog output:
baseString: 2KP7MAR5CX86

How to select range of values when using arc4random()

Can I set a range of numbers when using arc4random()? For example 50-100 only.
As pointed out in other posts below, it is better to use arc4random_uniform. (When this answer was originally written, arc4random_uniform was not available). Besides avoiding the modulo bias of arc4random() % x, it also avoids a seeding problem with arc4random when used recursively in short timeframes.
arc4random_uniform(4)
will generate 0, 1, 2 or 3. Thus you could use:
arc4random_uniform(51)
and merely add 50 to the result to get a range between 50 & 100 (inclusive).
To expand upon JohnK comment.
It is suggested that you use the following function to return a ranged random number:
arc4random_uniform(51)
which will return a random number in the range 0 to 50.
Then you can add your lower bounds to this like:
arc4random_uniform(51) + 50
which will return a random number in the range 50 to 100.
The reason we use arc4random_uniform(51) over arc4random() % 51 is to avoid the modulo bias. This is highlighted in the man page as follows:
arc4random_uniform(upper_bound) will return a uniformly distributed random number less than upper_bound. arc4random_uniform() is recommended over constructions like ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.
In short you get a more evenly distributed random number generated.
int fromNumber = 10;
int toNumber = 30;
int randomNumber = (arc4random()%(toNumber-fromNumber))+fromNumber;
Will generate randon number between 10 and 30, i.e. 11,12,13,14......29
You can use this code for generating random values with range:
//range from 50 to 100
int num1 = (arc4random() % 50) + 50; or
int num1 = arc4random_uniform(50) + 50;
//range from 0-100
int num1 = arc4random() % 100; or
int num1 = arc4random_uniform(100);
In Swift you can use this (inspired by answer of #Justyn)
func generateRandomKey(fromRange rangeFrom:Int, toRange rangeTo:Int) -> Int{
let theKey = arc4random_uniform(UInt32(rangeTo - rangeFrom)) + UInt32(rangeFrom)
return Int(theKey)
}
Will always give you a random range Integer.
In many situations 10 thru 30 would mean inclusive, (includes 10 and 30) ...
int fromNumber = 10;
int toNumber = 30;
toNumber ++;
int randomNumber = (arc4random()%(toNumber-fromNumber))+fromNumber;
Notice the difference toNumber - fromNumber is now 21 ... (20+1) which yields the possible results of 0 thru 20 (inclusive) which when added to fromNumber (10) results in 10 thru 30 (inclusive).

Resources