objc struct array to swift array - objective-c

-(CGPoint*)func
{
CGPoint* result = calloc(2, sizeof(CGPoint));
result[0] = ..;
result[1] = ..;
return result;
}
how cast this array to swift [CGPoint] ?

You can use UnsafeBufferPointer to cast it as follows
let pointer: UnsafeMutablePointer<CGPoint> = yourInstance.func()
let swiftArray = Array(UnsafeBufferPointer(start: pointer, count: 2))
free(pointer)
EDIT
If you really need to use C arrays, you may want to rewrite the func method to something like:
- (CGPoint*)pointArray:(NSInteger *)length
{
int arrSize = 2;
CGPoint* result = calloc(arrSize, sizeof(CGPoint));
result[0] = ...
result[1] = ...
*length = arrSize;
return result;
}
Then on the Swift side:
var arrayLength: Int = 0
let pointer: UnsafeMutablePointer<CGPoint> = yourInstance.pointArray(&arrayLength)
let swiftArray = Array(UnsafeBufferPointer(start: pointer, count: arrayLength))
free(pointer)

Related

Swift 4, reading byte data

so I recently update my IMAC and Xcode, after updating part of my code wasn't running as its supposed to it. Here is where I originally check messages.
func checkForMessages() {
while true {
if inputBuffer.length < 4 {
return
}
var msgLength = (inputBuffer.bytes).load(as: UInt32.self)
msgLength = UInt32(bigEndian: msgLength)
print("msgLength = \(msgLength)")
print("inputBuffer Length = \(inputBuffer.length)")
print("inputBuffer = \(inputBuffer)")
if inputBuffer.length < msgLength {
return
}
//print("data = \(inputBuffer.subdata(with: NSRange(location: 4, length: Int(msgLength))))")
if inputBuffer.length < msgLength + 4 {
return
}
let message: Data? = inputBuffer.subdata(with: NSRange(location: 4, length: Int(msgLength)))
processMessage(message!)
let amtRemaining: Int = inputBuffer.length - Int(msgLength) - 4
if amtRemaining == 0 {
inputBuffer = NSMutableData()
}
else {
print("Creating input buffer of length \(amtRemaining)")
inputBuffer = NSMutableData(bytes: inputBuffer.bytes + 4 + Int(msgLength), length: amtRemaining)
}
}
}
and then the process message function
func processMessage(_ data: Data) {
let reader = MessageReader(data: data)
print("this is the message data\(data)")
let msgType = reader?.readByte().hashValue
}
and then the actually MessageReader, its in Objective C, since I pulled it off the internet a while ago. Its been working fine for me ever since. Until now.
#import "MessageReader.h"
#implementation MessageReader
- (id)initWithData:(NSData *)data {
if ((self = [super init])) {
_data = data;
_offset = 0;
}
return self;
}
- (unsigned char)readByte {
unsigned char retval = *((unsigned char *) (_data.bytes + _offset));
_offset += sizeof(unsigned char);
return retval;
}
- (int)readInt {
int retval = *((unsigned int *) (_data.bytes + _offset));
retval = ntohl(retval);
_offset += sizeof(unsigned int);
return retval;
}
- (NSString *)readString {
int strLen = [self readInt];
NSString *retval = [NSString stringWithCString:_data.bytes + _offset encoding:NSUTF8StringEncoding];
_offset += strLen;
return retval;
}
- (void)dealloc {
}
#end
Now the issue is that instead of returning the number for say “1” or “2”, “30”, etc. its returning some huge number like 1836718193728. I believe the issue lies in the messageReader, readByte function.
From your comment, reader?.readByte().hasValue is returning a huge number. (I believe hasValue is just a typo and its hashValue.)
That's a possible behavior of hashValue.
Are you using hashValue as if it's a UInt8 to Int conversion tool?
It's wrong. The property hashValue is (and should be) implemented to return some Int value which fulfills one axiom:
where a == b, a.hashValue == b.hashValue
In older versions of Swift, UInt8.hashValue may have returned the same value of type Int, but you should not rely on such an implementation detail that is not documented. A slight change of implementation would lead to different results.
And in fact, Swift 4.2 has changed the implementation of hashValue drastically.
SE-0206 Hashable Enhancements
You may need to fix all parts of your project using hashValue.
Usually, you use Int.init(_:) to convert UInt8 to Int.
In a context like Optional Chaining as shown in your let msgType, you may need to write something like this.
let msgType = (reader?.getByte()).map{Int($0)}
If you have many parts using hashValue wrongly, better write an extension:
extension UInt8 {
var integerValue: Int {
return Int(self)
}
}
let msgType = reader?.getByte().integerValue
Generally, you should better not include such wrong hacks in your project.

Trouble converting NSData Objective-C code to Swift

I've been having issues converting an Objective-C snippet to Swift that uses NSData and CoreBluetooth. I have looked at this question and a couple others dealing with NSData in Swift but haven't had any success.
Objective-C Snippet:
- (CGFloat) minTemperature
{
CGFloat result = NAN;
int16_t value = 0;
// characteristic is a CBCharacteristic
if (characteristic) {
[[characteristic value] getBytes:&value length:sizeof (value)];
result = (CGFloat)value / 10.0f;
}
return result;
}
What I have so far in Swift (not working):
func minTemperature() -> CGFloat {
let bytes = [UInt8](characteristic?.value)
let pointer = UnsafePointer<UInt8>(bytes)
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
value = Int16(fPointer.pointee)
result = CGFloat(value / 10) // not correct value
return result
}
Does the logic look wrong here? Thanks!
One error is in
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
because the rebound pointer $0 is only valid inside the closure and must
not be passed to the outside. Also the capacity should be 1 for a
single Int16 value. Another problem is the integer division in
result = CGFloat(value / 10)
which truncates the result (as already observed by the4kman).
Creating an [UInt8] array from the data is not necessary, the
withUnsafeBytes() method of Data can be used instead.
Finally you could return nil (instead of "not a number") if no
characteristic value is given:
func minTemperature() -> CGFloat? {
guard let value = characteristic?.value else {
return nil
}
let i16val = value.withUnsafeBytes { (ptr: UnsafePointer<Int16>) in
ptr.pointee
}
return CGFloat(i16val) / 10.0
}
You should make the return value optional and check if characteristic is nil in the beginning with a guard. You should also explicitly convert the value to CGFloat, then divide it by 10.
func minTemperature() -> CGFloat? {
guard characteristic != nil else {
return nil
  }
let bytes = [UInt8](characteristic!.value)
let pointer = UnsafePointer<UInt8>(bytes)
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
let value = Int16(fPointer.pointee)
result = CGFloat(value) / 10
return result
}

"Binary/Unary operator '++/<' cannot be applied to an operand of type" AND "Use of unresolved identifier '=-'"

I am translating an Obj-C app to Swift and having trouble dealing with some syntax. I believe I have declared the variable types correctly so I don't know why I'm be getting these errors. Maybe some blocks are located incorrectly inside classes/functions when they should be outside or something. I would love it if you could review my code. I'm new to programming so what may be a clear and explicit explanation to you probably will still be vague for me so please show with examples using existing names.
Thanks
"Unary operator '++' cannot be applied to an operand of type 'Int?'"
and
"Binary operator '<' cannot be applied to an operand of type 'Int? and Float'"
and
"Use of unresolved identifier '=-'"
import UIKit
import Foundation
import AVFoundation
let minFramesForFilterToSettle = 10
enum CurrentState {
case statePaused
case stateSampling
}
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
let session = AVCaptureSession()
var camera : AVCaptureDevice?
var validFrameCounter: Int = 0
var pulseDetector: PulseDetector!
var filter: Filter!
var currentState = CurrentState.stateSampling // Is this initialized correctly?
override func viewDidLoad() {
super.viewDidLoad()
self.pulseDetector = PulseDetector()
self.filter = Filter()
// TO DO startCameraCapture() // call to un-used function.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
let NZEROS = 10
let NPOLES = 10
class Filter {
var xv = [Float](count: NZEROS + 1, repeatedValue: 0)
var yv = [Float](count: NPOLES + 1, repeatedValue: 0)
func processValue(value: Float) -> Float {
let gain: Float = 1.894427025e+01
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; xv[8] = xv[9]; xv[9] = xv[10]; xv[10] = value / gain;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; yv[8] = yv[9]; yv[9] = yv[10];
yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
+ ( -0.0000000000 * yv[0]) + ( 0.0357796363 * yv[1])
+ ( -0.1476158522 * yv[2]) + ( 0.3992561394 * yv[3])
+ ( -1.1743136181 * yv[4]) + ( 2.4692165842 * yv[5])
+ ( -3.3820859632 * yv[6]) + ( 3.9628972812 * yv[7])
+ ( -4.3832594900 * yv[8]) + ( 3.2101976096 * yv[9]);
return yv[10];
}
}
let maxPeriod = 1.5 // float?
let minPeriod = 0.1 // float?
let invalidEntry:Double = -11
let maxPeriodsToStore:Int = 20
let averageSize:Float = 20
class PulseDetector {
var upVals: [Float] = [averageSize]
var downVals: [Float] = [averageSize]
var upValIndex: Int?
var downValIndex: Int?
var lastVal: Float?
var periodStart: Float?
var periods: [Double] = []
var periodTimes: [Double] = []
var periodIndex: Int?
var started: Bool?
var freq: Float?
var average: Float?
var wasDown: Bool?
func reset() {
for var i=0; i < maxPeriodsToStore; i++ {
periods[i] = invalidEntry
}
for var i=0; i < averageSize; i++ { // why error when PulseDetector.h said averageSize was an Int?
upVals[i] = invalidEntry
downVals[i] = invalidEntry
}
freq = 0.5
periodIndex = 0
downValIndex = 0
upValIndex = 0
}
func addNewValue(newVal:Float, atTime:Double) -> Float {
// we keep track of the number of values above and below zero
if newVal > 0 {
upVals[upValIndex!] = newVal
upValIndex++
if upValIndex >= averageSize {
upValIndex = 0
}
}
if newVal < 0 {
downVals[downValIndex] =- newVal
downValIndex++
if downValIndex >= averageSize {
downValIndex = 0
}
}
// work out the average value above zero
var count: Float
var total: Float
for var i=0; i < averageSize; i++ {
if upVals[i] != invalidEntry {
count++
total+=upVals[i]
}
}
var averageUp = total/count
// and the average value below zero
count=0;
total=0;
for var i=0; i < averageSize; i++ {
if downVals[i] != invalidEntry {
count++
total+=downVals[i]
}
}
var averageDown = total/count
// is the new value a down value?
if newVal < (-0.5*averageDown) {
wasDown = true
}
// original Objective-C code
PulseDetector.h
#import <Foundation/Foundation.h>
#define MAX_PERIODS_TO_STORE 20 // is this an Int?
#define AVERAGE_SIZE 20 // is this a Float?
#define INVALID_PULSE_PERIOD -1 // done
#interface PulseDetector : NSObject {
float upVals[AVERAGE_SIZE];
float downVals[AVERAGE_SIZE];
int upValIndex;
int downValIndex;
float lastVal;
float periodStart;
double periods[MAX_PERIODS_TO_STORE]; // this is an array!
double periodTimes[MAX_PERIODS_TO_STORE]; // this is an rray !!
int periodIndex;
bool started;
float freq;
float average;
bool wasDown;
}
#property (nonatomic, assign) float periodStart; // var periodStart = float?
-(float) addNewValue:(float) newVal atTime:(double) time; // declaring a method called addNewValue with 2 arguments called atTime and time that returns a float
-(float) getAverage; // declaring a method called getAverage that returns a float
-(void) reset; // declaring a method that returns nothing
#end
PulseDetector.m
#import <QuartzCore/QuartzCore.h>
#import "PulseDetector.h"
#import <vector>
#import <algorithm>
#define MAX_PERIOD 1.5
#define MIN_PERIOD 0.1
#define INVALID_ENTRY -100 // is this a double?
#implementation PulseDetector
#synthesize periodStart;
- (id) init
{
self = [super init];
if (self != nil) {
// set everything to invalid
[self reset];
}
return self;
}
-(void) reset {
for(int i=0; i<MAX_PERIODS_TO_STORE; i++) {
periods[i]=INVALID_ENTRY;
}
for(int i=0; i<AVERAGE_SIZE; i++) {
upVals[i]=INVALID_ENTRY;
downVals[i]=INVALID_ENTRY;
}
freq=0.5;
periodIndex=0;
downValIndex=0;
upValIndex=0;
}
-(float) addNewValue:(float) newVal atTime:(double) time {
// we keep track of the number of values above and below zero
if(newVal>0) {
upVals[upValIndex]=newVal;
upValIndex++;
if(upValIndex>=AVERAGE_SIZE) {
upValIndex=0;
}
}
if(newVal<0) {
downVals[downValIndex]=-newVal;
downValIndex++;
if(downValIndex>=AVERAGE_SIZE) {
downValIndex=0;
}
}
// work out the average value above zero
float count=0;
float total=0;
for(int i=0; i<AVERAGE_SIZE; i++) {
if(upVals[i]!=INVALID_ENTRY) {
count++;
total+=upVals[i];
}
}
float averageUp=total/count;
// and the average value below zero
count=0;
total=0;
for(int i=0; i<AVERAGE_SIZE; i++) {
if(downVals[i]!=INVALID_ENTRY) {
count++;
total+=downVals[i];
}
}
float averageDown=total/count;
// is the new value a down value?
if(newVal<-0.5*averageDown) {
wasDown=true;
}
// is the new value an up value and were we previously in the down state?
if(newVal>=0.5*averageUp && wasDown) {
wasDown=false;
// work out the difference between now and the last time this happenned
if(time-periodStart<MAX_PERIOD && time-periodStart>MIN_PERIOD) {
periods[periodIndex]=time-periodStart;
periodTimes[periodIndex]=time;
periodIndex++;
if(periodIndex>=MAX_PERIODS_TO_STORE) {
periodIndex=0;
}
}
// track when the transition happened
periodStart=time;
}
// return up or down
if(newVal<-0.5*averageDown) {
return -1;
} else if(newVal>0.5*averageUp) {
return 1;
}
return 0;
}
-(float) getAverage {
double time=CACurrentMediaTime();
double total=0;
double count=0;
for(int i=0; i<MAX_PERIODS_TO_STORE; i++) {
// only use upto 10 seconds worth of data
if(periods[i]!=INVALID_ENTRY && time-periodTimes[i]<10) {
count++;
total+=periods[i];
}
}
// do we have enough values?
if(count>2) {
return total/count;
}
return INVALID_PULSE_PERIOD;
}
#end
Your problem is that you didn't copied the defines:
#define MAX_PERIODS_TO_STORE 20 // is this an Int?
#define AVERAGE_SIZE 20 // is this a Float?
#define INVALID_PULSE_PERIOD -1 // done
You have to change your defines so they work in your Swift code.
Check this answer how to replace the Objective-C #define to make Swift-Workable.
Also you could just change the defines to variables and initialize your variables with them.
First, a bit on optionals. Variables that end with a '?' are Optional, meaning that they are allowed to be nil (basically not exist). The compiler will not know at compile time whether this variable exists or not, because you are allowed to set it to nil.
"Unary operator '++' cannot be applied to an operand of type 'Int?'"
You seem to have read that last word as Int, but it is Int? which is significant. Basically, since it is an optional (as indicated by the question mark), the compiler knows it can be nil. You cannot use ++ on nil, and since optionals can be nil, you cannot use ++ on optionals. You must forcibly unwrap it first:
downValIndex!++ //note the exclamation point for unwrapping
"Use of unresolved identifier '=-'"
=- isnt a thing. -= is a thing. So
downVals[downValIndex] -= newVal
downVals[downValIndex] = downVals[downValIndex]-newVal //equivalent to above
"Binary operator '>=' cannot be applied to an operand of type 'Int? and Float'"
The compiler thinks you have an optional int on the left of the < and a Float on the right. Assuming you want two Ints, you must unwrap the left and make sure the right is cast to be an int (something like this). If you want two floats instead, cast or define as floats instead of ints.
if downValIndex! >= averageSize as! Int { //casting to Int
You should just be defining averageSize as an int though
var averageSize:Int = 10 //or whatever number
Also, you have lots of optionals. If any of them can be defined to something at compile time, it will make your life easier as you won't need to unwrap them everywhere. Alternately you could implicitly unwrap them (only do this if you are absolutely sure they will never be nil).
var implicitlyUnwrappedOptional:Int!

Swift RC4 vs. Objective-C RC4 Performance

I have been trying to rewrite a Rc4-algorithm from objective-c to swift, to test out apples(now old) claims, about it running a lot faster.
However there must be somewhere that I am doing something horribly wrong with these times I am getting
This is the objective c code:
+(NSString*)Rc4:(NSString*)aInput key:(NSString *)aKey {
NSMutableArray *iS = [[NSMutableArray alloc] initWithCapacity:256];
NSMutableArray *iK = [[NSMutableArray alloc] initWithCapacity:256];
for (int i = 0; i <256;i++){
[iS addObject:[NSNumber numberWithInt:i]];
}
for(short i=0;i<256;i++){
UniChar c = [aKey characterAtIndex:i%aKey.length];
[iK addObject:[NSNumber numberWithChar:c]];
}
int j=2;
for (int i=0; i<255;i++){
int is = [[iS objectAtIndex:i] intValue];
UniChar ik = (UniChar)[[iK objectAtIndex:i]charValue];
j= (j+is+ik)%256;
NSNumber *temp = [iS objectAtIndex:i];
[iS replaceObjectAtIndex:i withObject:[iS objectAtIndex:j]];
[iS replaceObjectAtIndex:j withObject:temp];
}
int i =0;
j=0;
NSString *result = aInput;
for (short x=0;x<[aInput length]; x++){
i = (i+1)%256;
int is = [[iS objectAtIndex:i]intValue];
j=(j+is)%256;
int is_i = [[iS objectAtIndex:i]intValue];
int is_j = [[iS objectAtIndex:j]intValue];
int t= (is_i+is_j)%256;
int iY = [[iS objectAtIndex:t]intValue];
UniChar ch = (UniChar)[aInput characterAtIndex:x];
UniChar ch_y=ch^iY;
//NSLog(ch);
//NSLog(iY);
result = [result stringByReplacingCharactersInRange:NSMakeRange(x,1) withString:
[NSString stringWithCharacters:&ch_y length:1] ];
}
[iS release];
[iK release];
return result;
}
This runs pretty fast compiling with -O3 I get times of:
100 runs:0.006 seconds
With key: 6f7e2a3d744a3b5859725f412f (128bit)
and input: "MySecretCodeToBeEncryptionSoNobodySeesIt"
This is my attempt to implement it in the same way using Swift:
extension String {
subscript (i: Int) -> String {
return String(Array(self)[i])
}
}
extension Character {
func unicodeValue() -> UInt32 {
for s in String(self).unicodeScalars {
return s.value
}
return 0
}
}
func Rc4(input:String, key:String)-> String{
var iS = Array(count:256, repeatedValue: 0)
var iK = Array(count:256, repeatedValue: "")
var keyLength = countElements(key)
for var i = 0; i < 256; i++ {
iS[i] = i;
}
for var i = 0; i < 256 ; i++ {
var c = key[i%keyLength]
iK[i] = c;
}
var j = 2
for var i = 0; i < 255; i++ {
var iss = iS[i]
var ik = iK[i]
// transform string to int
var ik_x:Character = Character(ik)
var ikk_xx = Int(ik_x.unicodeValue())
j = (j+iss+ikk_xx)%256;
var temp = iS[i]
iS[i] = iS[j]
iS[j] = temp
}
var i = 0
j=0
var result = input
var eles = countElements(input)
for var x = 0 ; x<eles ; x++ {
i = (i+1)%256
var iss = iS[i]
j = (j+iss)%256
var is_i = iS[i]
var is_j = iS[j]
var t = (is_i+is_j)%256
var iY = iS[t]
var ch = (input[x])
var ch_x:Character = Character(ch)
var ch_xx = Int(ch_x.unicodeValue())
var ch_y = ch_xx^iY
var start = advance(result.startIndex, x)
var end = advance(start,1);
let range = Range(start:start, end:end)
var maybestring = String(UnicodeScalar(ch_y))
result = result.stringByReplacingCharactersInRange(range, withString:maybestring)
}
return result;
}
I have tried to implement it so it looks as much as the objective-c version as possible.
This however gives me these horrible times, using -O
100 runs: 0.5 seconds
EDIT
Code should now run in xcode 6.1 using the extension methods I posted.
I run it from terminal like this:
xcrun swiftc -O Swift.swift -o swift
where Swift.swift is my file, and swift is my executable
Usually claims of speed don't really apply to encryption algorithms, they are more for what I usually call "business logic". The functions on bits, bytes, 16/32/64 bit words etc. are usually difficult to optimize. Basically encryption algorithms are designed to be dense operations on these data structures with relatively few choices that can be optimized away.
Take for instance Java. Although infinitely faster than most interpreted languages it really doesn't compare well with C/C++, let alone with assembly optimized encryption algorithms. The same goes for most relatively small algebraic problems.
To make things faster you should at least use explicit numeric types for your numbers.
After excessive testing of the code, i have narrowed it down to what is making my times ultra slow.
If i comment out this code, so that the iK array just contains its initial value. i go from a runtime of 5 seconds to 1 second. Which is a significant increase.
for var i = 0; i < 256 ; i++ {
var c = key[i%keyLength]
iK[i] = c;
}
The problem is with this part:
var c = key[i%keyLength]
There is no "characterAtIndex(int)" method in Swift, therefore i do this as a workaround to get the characterAtIndex. I do it using my extension:
extension String {
subscript (i: Int) -> String {
return String(Array(self)[i])
}
}
But essentially it is the same as this:
var c = Array(key)[i%keyLength]
Instead of the O(1) - (constant time) of this operation in objective-c, we are getting a running time of O(n).

How to stop enumerateObjectsUsingBlock Swift

How do I stop a block enumeration?
myArray.enumerateObjectsUsingBlock( { object, index, stop in
//how do I stop the enumeration in here??
})
I know in obj-c you do this:
[myArray enumerateObjectsUsingBlock:^(id *myObject, NSUInteger idx, BOOL *stop) {
*stop = YES;
}];
In Swift 1:
stop.withUnsafePointer { p in p.memory = true }
In Swift 2:
stop.memory = true
In Swift 3 - 4:
stop.pointee = true
This has unfortunately changed every major version of Swift. Here's a breakdown:
Swift 1
stop.withUnsafePointer { p in p.memory = true }
Swift 2
stop.memory = true
Swift 3
stop.pointee = true
since XCode6 Beta4, the following way can be used instead:
let array: NSArray = // the array with some elements...
array.enumerateObjectsUsingBlock( { (object: AnyObject!, idx: Int, stop: UnsafePointer<ObjCBool>) -> Void in
// do something with the current element...
var shouldStop: ObjCBool = // true or false ...
stop.initialize(shouldStop)
})
The accepted answer is correct but will work for NSArrays only. Not for the Swift datatype Array. If you like you can recreate it with an extension.
extension Array{
func enumerateObjectsUsingBlock(enumerator:(obj:Any, idx:Int, inout stop:Bool)->Void){
for (i,v) in enumerate(self){
var stop:Bool = false
enumerator(obj: v, idx: i, stop: &stop)
if stop{
break
}
}
}
}
call it like
[1,2,3,4,5].enumerateObjectsUsingBlock({
obj, idx, stop in
let x = (obj as Int) * (obj as Int)
println("\(x)")
if obj as Int == 3{
stop = true
}
})
or for function with a block as the last parameter you can do
[1,2,3,4,5].enumerateObjectsUsingBlock(){
obj, idx, stop in
let x = (obj as Int) * (obj as Int)
println("\(x)")
if obj as Int == 3{
stop = true
}
}
Just stop = true
Since stop is declared as inout, swift will take care of mapping the indirection for you.