Can not pass arguments to CFSwapInt16LittleToHost correctly in Swift - objective-c

I am converting code from Objective-C to Swift and am having trouble with the casting especially for byte operations. In particular, I am getting the error 'Can not invoke CFSwapInt16LittleToHost with an argument list of (Int16)'. The Objective-C code is:
#interface THSampleDataFilter ()
#property (nonatomic, strong) NSData *sampleData;
#end
#implementation THSampleDataFilter
- (id)initWithData:(NSData *)sampleData {
self = [super init];
if (self) {
_sampleData = sampleData;
}
return self;
}
- (NSArray *)filteredSamplesForSize:(CGSize)size {
NSMutableArray *filteredSamples = [[NSMutableArray alloc] init];
NSUInteger sampleCount = self.sampleData.length / sizeof(SInt16);
NSUInteger binSize = sampleCount / size.width;
SInt16 *bytes = (SInt16 *) self.sampleData.bytes;
SInt16 maxSample = 0;
for (NSUInteger i = 0; i < sampleCount; i += binSize) {
SInt16 sampleBin[binSize];
for (NSUInteger j = 0; j < binSize; j++) {
sampleBin[j] = CFSwapInt16LittleToHost(bytes[i + j]);
}
SInt16 value = [self maxValueInArray:sampleBin ofSize:binSize];
[filteredSamples addObject:#(value)];
if (value > maxSample) {
maxSample = value;
}
}
My Swift code is:
class THSampleDataFilter : NSObject
{
var sampleData: NSData?
init(sampleData: NSData)
{
super.init()
self.sampleData = sampleData
}
func filteredSamplesForSize(size: CGSize) -> NSArray?
{
var filteredSamples = NSMutableArray()
var sampleCount:UInt = UInt(Int(self.sampleData!.length) / Int(sizeof(Int16)))
var binSize = UInt(sampleCount / UInt(size.width))
var bytes: UnsafePointer<Int16> = UnsafePointer<Int16>(self.sampleData!.bytes)
var maxSample: Int16 = 0
for var i:UInt = 0; i < sampleCount; i = i + binSize
{
var sampleBin: [Int16] = []
for var j: UInt = 0; j < binSize; j++
{
sampleBin.append(CFSwapInt16LittleToHost(bytes[i + j]))
}
let value: Int16 = self.maxValueInArray(sampleBin, size: binSize)
filteredSamples.addObject(NSNumber(short: value))
if value > maxSample
{
maxSample = value
}
}
The problem line is:
sampleBin.append(CFSwapInt16LittleToHost(bytes[i + j]))
This is when I get the error 'Can not invoke CFSwapInt16LittleToHost with an argument list of (Int16)'. I have tried every combination I can think of.
Any help would be greatly appreciated!
Thank you for looking.

CFSwapInt16LittleToHost takes a UInt16, not an Int16.
sampleBin.append(CFSwapInt16LittleToHost(UInt16(bytes[i + j])))
or change bytes to a UInt16 pointer.
var bytes: UnsafePointer<UInt16> = UnsafePointer<UInt16>(self.sampleData!.bytes)

Related

how Hexadecimal string to Bytes

how hexadecimal string to Bytes and Bytes to hexadecimal string?
I have oc code but I can not to write in swift
can u help me ?
thanks so much
+ (NSData *)convertHexToDataBytes:(NSString *)hexStr {
NSMutableData *dataBytes = [NSMutableData data];
int idx;
for (idx = 0; idx + 2 <= hexStr.length; idx += 2) {
NSRange range = NSMakeRange(idx, 2);
NSString *singleHexStr = [hexStr substringWithRange:range];
NSScanner *scanner = [NSScanner scannerWithString:singleHexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[dataBytes appendBytes:&intValue length:1];
}
return dataBytes;
}
+ (NSString *)convertDataBytesToHex:(NSData *)dataBytes {
if (!dataBytes || [dataBytes length] == 0) {
return #"";
}
NSMutableString *hexStr = [[NSMutableString alloc] initWithCapacity:[dataBytes length]];
[dataBytes enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char *)bytes;
for (NSInteger i = 0; i < byteRange.length; i ++) {
NSString *singleHexStr = [NSString stringWithFormat:#"%x", (dataBytes[i]) & 0xff];
if ([singleHexStr length] == 2) {
[hexStr appendString:singleHexStr];
} else {
[hexStr appendFormat:#"0%#", singleHexStr];
}
}
}];
return hexStr;
}
I write in swift like this
class func convertHex(toDataBytes hexStr: String?) -> Data? {
var dataBytes = Data()
var idx: Int
idx = 0
while idx + 2 <= (hexStr?.count ?? 0) {
let range = NSRange(location: idx, length: 2)
let singleHexStr = (hexStr as NSString?)?.substring(with: range)
let scanner = Scanner(string: singleHexStr ?? "")
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
dataBytes.append(&intValue, count: 1)
idx += 2
}
return dataBytes
}
its error says:Cannot pass immutable value as inout argument: function call returns immutable value how to fix it?
To answer your immediate question: UInt32(intValue) creates a new (constant) value whose address cannot be taken with &. So
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
should be
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
And
dataBytes.append(&intValue, count: 1)
does not compile because &intValue is a pointer to an integer, not to an UInt8. Here you can do
dataBytes.append(UInt8(intValue))
because the value is known to fit in a single byte.
Having said that, all the conversions from String to NSString are not needed. A more “Swifty” translation of that Objective-C code to Swift would be
func convertHex(toDataBytes hexStr: String) -> Data {
var dataBytes = Data()
var startPos = hexStr.startIndex
while let endPos = hexStr.index(startPos, offsetBy: 2, limitedBy: hexStr.endIndex) {
let singleHexStr = hexStr[startPos..<endPos]
let scanner = Scanner(string: String(singleHexStr))
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
dataBytes.append(UInt8(intValue))
startPos = endPos
}
return dataBytes
}
For an alternative approach (which includes error checking) see for example
hex/binary string conversion in Swift

Find Max Difference in Array - Need Algorithm Solution Optimization [duplicate]

This question already has answers here:
optimal way to find sum(S) of all contiguous sub-array's max difference
(2 answers)
Closed 6 years ago.
I practised solving an algo on HackerRank - Max Difference.
Here's the problem given:
You are given an array with n elements: d[ 0 ], d[ 1 ], ..., d[n-1]. Calculate the sum(S) of all contiguous sub-array's max difference.
Formally:
S = sum{max{d[l,...,r]} - min{d[l, ..., r}},∀ 0 <= l <= r < n
Input format:
n
d[0] d[1] ... d[n-1]
Output format:
S
Sample Input:
4
1 3 2 4
Sample Output:
12
Explanation:
l = 0; r = 0;
array: [1]
sum = max([1]) - min([1]) = 0
l = 0; r = 1;
array: [1,3]
sum = max([1,3]) - min([1,3]) = 3 - 1 = 2
l = 0; r = 2;
array: [1,3,2]
sum = max([1,3,2]) - min([1,3,2]) = 3 - 1 = 2
l = 0;r = 3;
array: [1,3,2,4]
sum = max([1,3,2,4]) - min([1,3,2,4]) = 4 - 1 = 3
l = 1; r = 1 will result in zero
l = 1; r = 2;
array: [3,2]
sum = max([3,2]) - min([3,2]) = 3 - 2 = 1;
l = 1; r = 3;
array: [3,2,4]
sum = max ([3,2,4]) - min([3,2,4]) = 4 - 2 = 2;
l = 2; r = 2; will result in zero
l = 2; r = 3;
array:[2,4]
sum = max([2,4]) - min([2,4]) = 4 -2 = 2;
l = 3; r = 3 will result in zero;
Total sum = 12
Here's my solution:
-(NSNumber*)sum:(NSArray*) arr {
int diff = 0;
int curr_sum = diff;
int max_sum = curr_sum;
for(int i=0; i<arr.count; i++)
{
for(int j=i; j<=arr.count; j++) {
// Calculate current diff
if (!(j-i > 1)) {
continue;
}
NSArray *array = [arr subarrayWithRange:NSMakeRange(i, j-i)];
if (!array.count || array.count == 1) {
continue;
}
int xmax = -32000;
int xmin = 32000;
for (NSNumber *num in array) {
int x = num.intValue;
if (x < xmin) xmin = x;
if (x > xmax) xmax = x;
}
diff = xmax-xmin;
// Calculate current sum
if (curr_sum > 0)
curr_sum += diff;
else
curr_sum = diff;
// Update max sum, if needed
if (curr_sum > max_sum)
max_sum = curr_sum;
}
}
return #(max_sum);
}
There were totally 10 test cases.
The above solution passed first 5 test cases, but didn't get passed through the other 5, which were failed due to time out (>=2s).
"Here's the Status: Terminated due to timeout".
Please help me on how this code can be further optimised.
Thanks!
Already there was an answer in Python. Here's the Objective C version from me:
#interface Stack : NSObject {
NSMutableArray* m_array;
int count;
}
- (void)push:(id)anObject;
- (id)pop;
- (id)prev_prev;
- (void)clear;
#property (nonatomic, readonly) NSMutableArray* m_array;
#property (nonatomic, readonly) int count;
#end
#implementation Stack
#synthesize m_array, count;
- (id)init
{
if( self=[super init] )
{
m_array = [[NSMutableArray alloc] init];
count = 0;
}
return self;
}
- (void)push:(id)anObject
{
[m_array addObject:anObject];
count = m_array.count;
}
- (id)pop
{
id obj = nil;
if(m_array.count > 0)
{
obj = [m_array lastObject];
[m_array removeLastObject];
count = m_array.count;
}
return obj;
}
- (id)prev_prev
{
id obj = nil;
if(m_array.count > 0)
{
obj = [m_array lastObject];
}
return obj;
}
- (void)clear
{
[m_array removeAllObjects];
count = 0;
}
#end
#interface SolutionClass:NSObject
/* method declaration */
-(NSNumber*)findDiff:(NSArray*) arr;
#end
#implementation SolutionClass
-(NSNumber*)findDiff:(NSArray*) arr {
NSNumber *maxims = [self sum:arr negative:NO];
NSNumber *minims = [self sum:arr negative:YES];
NSNumber *diff = #(maxims.longLongValue+minims.longLongValue);
NSLog(#"diff: %#", diff);
return diff;
}
-(NSNumber*)sum:(NSArray*) arr negative:(BOOL)negate {
Stack *stack = [Stack new];
[stack push:#{#(-1): [NSNull null]}];
long long sum = 0;
for(int i=0; i<arr.count; i++) {
NSNumber *num = arr[i];
if (negate) {
num = #(-num.longLongValue);
}
NSDictionary *prev = stack.m_array.lastObject;
NSNumber *prev_i = (NSNumber*)prev.allKeys[0];
NSNumber *prev_x = (NSNumber*)prev.allValues[0];
if ([self isNumber:prev_x]) {
while (num.longLongValue > prev_x.longLongValue) {
prev_i = (NSNumber*)prev.allKeys[0];
prev_x = (NSNumber*)prev.allValues[0];
prev = [stack pop];
NSDictionary *prev_prev_Dict = [stack prev_prev];
NSNumber *prev_prev_i = (NSNumber*)prev_prev_Dict.allKeys[0];
sum += prev_x.longLongValue * (i-prev_i.longLongValue) * (prev_i.longLongValue - prev_prev_i.longLongValue);
prev = stack.m_array.lastObject;
prev_x = (NSNumber*)prev.allValues[0];
if (![self isNumber:prev_x]) {
break;
}
}
}
[stack push:#{#(i): num}];
}
NSLog(#"Middle: sum: %lld", sum);
while (stack.count > 1) {
NSDictionary *prev = [stack pop];
NSDictionary *prev_prev_Dict = [stack prev_prev];
NSNumber *prev_i = (NSNumber*)prev.allKeys[0];
NSNumber *prev_x = (NSNumber*)prev.allValues[0];
NSNumber *prev_prev_i = (NSNumber*)prev_prev_Dict.allKeys[0];
sum += prev_x.longLongValue * (arr.count-prev_i.longLongValue) * (prev_i.longLongValue - prev_prev_i.longLongValue);
prev = stack.m_array.lastObject;
prev_x = (NSNumber*)prev.allValues[0];
if (![self isNumber:prev_x]) {
break;
}
}
NSLog(#"End: sum: %lld", sum);
return #(sum);
}
-(BOOL)isNumber:(id)obj {
if ([obj isKindOfClass:[NSNumber class]]) {
return 1;
}
return 0;
}
#end
The above solution works well for 7 test cases, but fails for the other 3 saying this: "Status: Wrong Answer". Hoping to find a fix for that too.
EDIT:
Have updated the WORKING code that passed all the test cases. Wrong data types were used before.

How to convert an array of NSString to an array of c-strings?

I have an NSArray<NSString*>* object, and I need to invoke a C API which takes in an array of strings as char**.
What's the best way to do this? The important note is the c-strings must not have a const modifier, so something like the following isn't good enough since UTF8String returns const char*:
NSArray<NSString*>* names = ...;
int len = args.count;
char* cNames[len];
for( int i = 0; i < len; i++ ) {
cNames[i] = names[i].UTF8String;
};
You will want to do some dynamic memory as you cannot rely on the backing memory for UTF8String being released.
NSArray *strings = #[ #"String 1", #"Other string", #"Random String"];
char **cStrings = NULL;
NSInteger numCStrings = strings.count;
if (numCStrings) {
cStrings = (char **)calloc(numCStrings, sizeof(char*)) ;
if (cStrings) {
// Safer to allocate memory for each string
for (NSInteger i=0;i<numCStrings;i++) {
NSString *nsString = strings[i];
char *cString = (char *)malloc([nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); // + 1 for \0
if (cString) {
strcpy(cString, nsString.UTF8String);
cStrings[i] = cString;
} else {
// You should handle your error
}
}
} else {
// You should handle your error
}
}
for (NSInteger i=0;i<numCStrings;i++) {
NSLog(#"C-String (%ld): %s", i, cStrings[i]);
}
// Note you need to free your memory later!
// Do any additional setup after loading the view, typically from a nib.
for (NSInteger i=0;i<numCStrings;i++) {
if (cStrings[i]) {
// Free each string
free(cStrings[i]);
}
}
// Free the array
free(cStrings);
cStrings = NULL;
numCStrings = 0;

Accessing objects when changing from NSMutableArray to NSMutableDictionary

In one of my classes I have changed from an NSMutableArray to a NSMutableDictionary.
Before I accessed objects from other class like this:
tmpDeadline = [_taskDays[i] deadline]; //deadline is a object of another class
And accessed methods like this:
[_taskDays[datePlace]addDatedTask:d]; //addDatedTask is a method in another class
But now I can't do this anymore since I get a lot of errors which I don't really know how to handle.
What I do know is that I want use the other class's "deadline" as key and the instance of the class as object.
Here is the code (I have given the code that gives me problem the comment ERROR:
#import "LIUTaskCalendar.h"
#import "LIUTaskDay.h"
#import "LIUDatedTask.h"
#interface LIUTaskCalendar ()
{
NSMutableDictionary *_taskDays;
}
#end
#implementation LIUTaskCalendar
- (void)addDatedTasks:(LIUDatedTask *)d {
if (!_taskDays) {
_taskDays = [[NSMutableDictionary alloc] init];
}
NSInteger length = [_taskDays count];
NSDate *tmpDeadline;
NSDate *tmpDueDate;
NSInteger dateExist = 0;
NSInteger datePlace = 0;
NSDate *tmp;
for (int i = 0; i < length; i++) {
tmpDueDate = d.dueDate;
tmpDeadline = [_taskDays[i] deadline]; //*ERROR*
if ([tmpDueDate compare:tmpDeadline] == NSOrderedAscending) {
continue;
} else if ([tmpDueDate compare:tmpDeadline] == NSOrderedDescending) {
continue;
} else {
dateExist = 1;
datePlace = i;
break;
}
}
if (dateExist == 1) {
[_taskDays[datePlace]addDatedTask:d]; //*ERROR*
} else {
LIUTaskDay *tmpLIUTaskDay = [[LIUTaskDay alloc]init];
[tmpLIUTaskDay addDatedTask:d];
tmpLIUTaskDay.deadline = d.dueDate;
//[_taskDays setObject:d forKey:tmpLIUTaskDay.deadline];
[_taskDays addObject:tmpLIUTaskDay]; //*ERROR*
}
}
- (void)removeTaskDay:(NSDate *)date {
NSDate *tmpDeadline;
NSDate *tmpDeleteDate;
NSInteger dateExist = 0;
NSDate *dateDelete;
NSInteger length = [_taskDays count];
for (int i = 0; i < length; i++) {
tmpDeleteDate = date;
tmpDeadline = [_taskDays[i] deadline]; //*ERROR*
if ([tmpDeleteDate compare:tmpDeadline] == NSOrderedAscending) {
continue;
} else if ([tmpDeleteDate compare:tmpDeadline] == NSOrderedDescending) {
continue;
} else {
dateExist = 1;
break;
}
}
if (dateExist == 1) {
//[_taskDays removeObjectForKey:dateDelete];
[_taskDays removeObjectAtIndex:dateDelete]; //*ERROR*
} else {
return;
}
}
#end
If you need me to provide the code for the other class to then don't
hesitate to tell me.
Thanks in advance
UPDATE
Changed from this:
[_taskDays addObject:tmpLIUTaskDay];
To this:
[_taskDays setObject:d forKey:tmpLIUTaskDay.deadline];
taskDays is dictionary, while you are using it as if it is an array _taskDays[i] in
tmpDeadline = [_taskDays[i] deadline]; //*ERROR*
also here:
[_taskDays addObject:tmpLIUTaskDay]; //*ERROR*
To fetch from dictionary or add a new key-value pair you should do like this:
tmpDeadline = [_taskDays[#"taskDay"] deadline];
and
[_taskDays addObject:addObject:tmpLIUTaskDay forKey:#"taskDay"];

Calculate LRC in Objective c

I want to calculate the LRC of a message that I send via Bluetooth. Here is for example a message :
(The message structure is STX MESSAGE FS EXT LRC)
02 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR 1C 03 60
STX = 02
MESSAGE = 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR
FS = 1C
EXT = 03
LRC = 60
What I have to do is calculate the LRC by performing a modulo 2 binary sum of every character in the communication message excluding the STX character but including the EXT characterr.
Before to calculate the LRC, I have to convert this NSString in HexaString :
31323132 30303431 32333432 32383236 45304238 43304630 30304630 41303031 38323632 30303030 54485952 4f4e2053 59535445 4d532057 4154464f 52442055 4b521c03
Method used :
- (NSString *) stringToHex:(NSString *)str
{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
[hexString appendFormat:#"%02x", chars[i]];
}
free(chars);
return [hexString autorelease];
}
And then I have to convert it in Byte Array.
Method used :
- (NSData*) hexToBytes:(NSString *) hexaStr {
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexaStr.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString * hexStrTmp = [hexaStr substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStrTmp];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
And then I try to do calculate my LRC, that should be 60, with the following :
- (void) calculateLRC:(NSString *) text {
NSData * data = [self hexToBytes:text];
NSUInteger size = [data length] / sizeof(const char);
const char * array = (const char*) [data bytes];
char checksum = 0;
for( uint32_t i = 0 ; i < size; i++) {
checksum += * array++;
}
NSLog(#"Checksum = %c", checksum);
self.LRC_Check = checksum;
}
The problem is that "checksum" has not the value "60" in it. Can someone help me with that please ?
Thanx in advance !
I have the answer !
In the method - (void) calculateLRC:(NSString *) text I have to replace :
checksum += * array++;
with :
checksum ^= * array++;
I thougt the Modulo character was "%" in Objective C...
I needed to do this in swift
this seems to work . .need to do some rigorous testing though..
var str = computeLRC(hexString:"373203")
print(str)
// returns 06
func computeLRC (hexString: String ) -> String {
var checksum : UInt16 = 0
var my = ""
for i in stride(from: 0, to: hexString.count, by: 2) {
let indexStartOfText = hexString.index( hexString.startIndex, offsetBy: i)
let indexEndOfText = hexString.index( indexStartOfText, offsetBy: 2)
let substring3 = hexString[indexStartOfText..<indexEndOfText]
let intResult = Int(String(substring3) , radix: 16)
guard let myUnicodeScalar = UnicodeScalar(intResult!) else {
return ""
}
// convert UnicodeScalar to Character
let myCharacter = Character(myUnicodeScalar)
my += String(myCharacter)
}
for myChar in my {
var byte: UInt16 = Array(String(myChar).utf16)[0]
checksum ^= byte
}
return String(format:"%02X", checksum)
}