I am trying to implement the following code in swift. But my i variable refuse to talk to my MAXADDRS. It says binary operator < cannot be applied to Clong in Swift. If I use CInt the problem goes away, but then I get an error on the variable i when assiginin theAddr = ip_addrs[i]
InitAddresses();
GetIPAddresses();
GetHWAddresses();
var i = CLong()
var deviceIP = NSString()
for (i=0; i < MAXADDRS; ++i)
{
var localHost = 0x7F000001; // 127.0.0.1
var theAddr = CLong()
theAddr = ip_addrs[i]
if (theAddr == 0) {return}
if (theAddr == localHost){continue}
NSLog("Name: %s MAC: %s IP: %s\n", if_names[i], hw_addrs[i], ip_names[i]);
//decided what adapter you want details for
if (strncmp(if_names[i], "en", 2) == 0)
{
NSLog("Adapter en has a IP of %s", ip_names[i]);
}
}
// Do any additional setup after loading the view, typically from a nib.
}
The MAXADDRS it intends to compare relates to the following OBC header
Source files here
http://www.chrisandtennille.com/code/IPAddress.h
http://www.chrisandtennille.com/code/IPAddress.c
My bridging header
#include "IPAddress.h"
#include "IPAddress.c"
#define MAXADDRS 32
is imported to Swift as
public var MAXADDRS: Int32 { get }
On the other hand, CLong is an alias for Int ("The C 'long' type.")
Therefore you need to convert all values to a common type. Since
array subscripting requires an Int index, converting MAXADDRS
to Int might be the easiest solution:
var i = 0 // Int
for (i=0; i < Int(MAXADDRS); ++i) {
}
or more simply:
for i in 0 ..< Int(MAXADDRS) {
}
Related
I am trying to get some data about a process in Swift.
I am using this code as a starting point:
pid_t pid = 10000;
rusage_info_current rusage;
if (proc_pid_rusage(pid, RUSAGE_INFO_CURRENT, (void **)&rusage) == 0)
{
cout << rusage.ri_diskio_bytesread << endl;
cout << rusage.ri_diskio_byteswritten << endl;
}
taken from Per Process disk read/write statistics in Mac OS X.
However, I have trouble converting the code above to Swift:
var usage = rusage_info_v3()
if proc_pid_rusage(100, RUSAGE_INFO_CURRENT, &usage) == 0
{
Swift.print("Success")
}
The function prod_pid_rusage expects a parameter of type rusage_info_t?, but I can not instantiate an instance of that type.
Is it possible to use the function in Swift?
Regards,
Sascha
As in C you have to take the address of a rusage_info_current
variable and cast it to the type expected by proc_pid_rusage().
In Swift this is done using withUnsafeMutablePointer()
and withMemoryRebound():
let pid = getpid()
var usage = rusage_info_current()
let result = withUnsafeMutablePointer(to: &usage) {
$0.withMemoryRebound(to: rusage_info_t?.self, capacity: 1) {
proc_pid_rusage(pid, RUSAGE_INFO_CURRENT, $0)
}
}
if result == 0 {
print(usage.ri_diskio_bytesread)
// ...
}
You have to add
#include <libproc.h>
to the bridging header file to make it compile.
I'm currently converting C++ code to Swift and I've gotten stuck on one part. The parameter passed into the function is a string and the area where I'm stuck is when attempting to set a variable based on the second to last character of a string to check for a certain character.
The error shows up on this line:
line[i-1]
I've tried casting this value to an Int but this didn't work:
Int(line[i - 1])
I've also tried to see if the string's startIndex function which takes a Int would work but it didn't:
line.startIndex[i - 1]
Here is the full function:
func scanStringForSpecificCharacters(line: String){
var maxOpen: Int = 0;
var minOpen: Int = 0;
minOpen = 0;
maxOpen = 0;
var i = 0
while i < line.characters.count {
for character in line.characters {
//var c: Character = line[i];
if character == "(" {
maxOpen += 1;
if i == 0 || line[i - 1] != ":" {
minOpen += 1;
}
}
else if character == ")"{
minOpen = max(0,minOpen-1);
if i == 0 || line[i-1] != ":"{
maxOpen -= 1;
}
if maxOpen < 0{
break;
}
}
}
if maxOpen >= 0 && minOpen == 0{
print("YES")
}else{
print("NO")
}
}
}
Strings in Swift aren't indexed collections and instead you can access one of four different views: characters, UTF8, UTF16, or unicodescalars.
This is because Swift supports unicode, where an individual characters may actually be composed of multiple unicode scalars.
Here's a post that really helped me wrap my head around this: https://oleb.net/blog/2016/08/swift-3-strings/
Anyway, to answer you question you'll need to create an index using index(after:), index(before:), or index(_, offsetBy:).
In your case you'd want to do something like this:
line.index(line.endIndex, offsetBy: -2) // second to last character
Also, you'll probably find it easier to iterate directly using a String.Index type rather than Int:
let line = "hello"
var i = line.startIndex
while i < line.endIndex {
print(line[i])
i = line.index(after: i)
}
// prints ->
// h
// e
// l
// l
// o
Working with Strings in Swift was changed several times during it's evolution and it doesn't look like C++ at all. You cannot subscript string to obtain individual characters, you should use index class for that. I recommend you read this article:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html
As already pointed out in the other answers, the compiler error
is caused by the problem that you cannot index a Swift String with
integers.
Another problem in your code is that you have a nested loop which is
probably not intended.
Actually I would try to avoid string indexing at all and only
enumerate the characters, if possible. In your case, you can
easily keep track of the preceding character in a separate variable:
var lastChar: Character = " " // Anything except ":"
for char in line.characters {
if char == "(" {
maxOpen += 1;
if lastChar != ":" {
minOpen += 1;
}
}
// ...
lastChar = char
}
Or, since you only need to know if the preceding character is
a colon:
var lastIsColon = false
for char in string.characters {
if char == "(" {
maxOpen += 1;
if !lastIsColon {
minOpen += 1;
}
}
// ...
lastIsColon = char == ":"
}
Another possible approach is to iterate over the string and a shifted
view of the string in parallel:
for (lastChar, char) in zip([" ".characters, line.characters].joined(), line.characters) {
// ...
}
As others have already explained, trying to index into Swift strings is a pain.
As a minimal change to your code, I would recommend that you just create an array of the characters in your line up front:
let linechars = Array(line.characters)
And then anywhere you need to index into the line, use linechars:
This:
if i == 0 || line[i-1] != ":" {
becomes:
if i == 0 || linechars[i-1] != ":" {
I have update Xcode to 7.3 and now I have a warning to the function that I use to create random strings.
I have tried to change the for statement with for (i in 0 ..< len){...} however, the warning became an error.
How can I remove the warning?
static func randomStringWithLength (len : Int) -> NSString {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: len)
for (var i=0; i < len; i += 1){ // warning
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
return randomString
}
C-style for loop has been deprecated in Swift 3. You can continue using it for a while, but they will certainly disappear in the future.
You can rewrite your loop to Swift's style:
for i in 0..<len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Since you don't use i at all in the loop's body, you can replace it with:
for _ in 0..<len {
// do stuffs
}
This BLOG saved my life.
INCREMENTING
for i in 0 ..< len {
}
DECREMENTING
for i in (0 ..< len).reverse() {
}
NON-SEQUENTIAL INDEXING
Using where
for i in (0 ..< len) where i % 2 == 0 {
}
Using striding to or through
for i in 0.stride(to: len, by: 2) {
}
in Swift 3 it's been an error
some general replacement was posted and just add
For Swift 3 and need to change the "index"
for var index in stride(from: 0, to: 10, by: 1){}
I've had success with the following. You can use the for loop as follows - note that the for loop is inclusive so you may need to check that len is actually greater than 0:
for i in 0...len - 1 {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Or you can use this:
for i in 0 ..< len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
BTW it appears XCode 7.x does help you to get there but it's a two step process. First you have to change your increment operator from (say) i++ to i += 1 and then XCode warning helps you modify the loop.
Following my previous question, I'm now having trouble overriding opIndex with variadic parameters. I've tried multiple methods (even hack-ish ones) but to no avail.
The code I'm using to generate the identifier string
static string array_decl(D...)(string identifier, D dimensions)
{
static if(dimensions.length == 0)
{
return identifier;
}
else
{
return array_decl(identifier ~ "[" ~ to!(string)(dimensions[0]) ~ "]", dimensions[1..$]);
}
}
What my opIndex override looks like:
T opIndex(D...)(D indices)
{
mixin("return " ~ array_decl("Data", indices) ~ ";");
}
Fails with:
./inheritance.d(81): Error: tuple D is used as a type
./inheritance.d(89): Error: template instance inheritance.array_ident!(int, int, int).array_ident.array_ident!(_param_2, _param_3) error instantiating
./inheritance.d(112): instantiated from here: array_ident!(int, int, int)
./inheritance.d(174): instantiated from here: opIndex!(int, int, int)
./inheritance.d(112): Error: CTFE failed because of previous errors in array_ident
./inheritance.d(112): Error: argument to mixin must be a string, not ("return " ~ array_ident("Data", _param_0, _param_1, _param_2) ~ ";") of type string
The question is how (or is it possible) to implement the opIndex operator for this situation.
I think mixins are the way to go since I only have to generate a string with the format of:
type[index0][index1]...[indexN] Data
for the opIndex overload.
Apparently this is not possible as the tuple passed to opIndex is inaccessible at compile-time. A few solutions I came up with (by Adam D. Ruppe's suggestions):
1. Hard-coding Array Access
Using compile-time conditions to index the array, a bit ugly and the amount of dimensions that can be accessed depends on the amount of conditions implemented.
T opIndex(D...)(D indices)
{
static if(indices.length == 1)
{
return Data[indices[0]];
}
static if(indices.length == 2)
{
return Data[indices[0]][indices[1]];
}
static if(indices.length == 3)
{
return Data[indices[0]][indices[1]][indices[2]];
}
static if(indices.length == 4)
{
return Data[indices[0]][indices[1]][indices[2]][indices[3]];
}
}
2. Pointer(s)
The only other method was to cast the array to a pointer then use offsets. The offset is computed and is then used to index the pointer.
To be able to access the template parameters at run-time:
struct Vector_MultiDim(T, D...)
{
enum dimensions = [D];
static const size_t DimCount = D.length;
... Other members here
}
Function to compute offset (the size of each dimension must be known at run-time):
size_t GetIndex(size_t[] indices)
{
size_t index;
for(size_t i = 0; i < DimCount; i++)
{
size_t factor = 1;
for(size_t j = i + 1; j < DimCount; j++)
{
factor *= dimensions[j];
}
index += indices[i] * factor;
}
return index;
}
opIndex Override:
T opIndex(D...)(D indices)
{
T* arr = cast(T*)Data;
return arr[GetIndex([indices])];
}
I'm trying to convert AudioStreamBasicDescription's mFormatID property, which I get with AudioFileGetGlobalInfo, to a readable string.
In Objective-C it looks like this:
for (int i = 0; i < asbdCount; i++) {
UInt32 format4cc = CFSwapInt32HostToBig(asbds[i].mFormatID);
NSLog(#"mFormatID: %4.4s", (char*)&format4cc);
}
This code is a piece of CAStreamFormatTester from the Learning Core Audio book. asbds is a pointer to AudioStreamBasicDescriptions. How to convert this into Swift?
If asbds is of type UnsafePointer<AudioStreamBasicDescription> or of type [AudioStreamBasicDescription], then I believe this should work:
for i in 0 ..< asbdCount {
var format4cc = CFSwapInt32HostToBig(asbds[i].mFormatID)
withUnsafePointer(&format4cc) { cptr in
println(String(format: "mFormatID: %4.4s", cptr))
}
}