Is there a way to call C routines from Swift?
A lot of iOS / Apple libraries are C only and I\'d still like to be able to call those.
For example, I\'d like
This post also has a good explanation regarding how to do this using clang's module support.
It's framed in terms of how to do this for the CommonCrypto project, but in general it should work for any other C library you want to use from within Swift.
I briefly experimented with doing this for zlib. I created a new iOS framework project and created a directory zlib, containing a module.modulemap file with the following:
module zlib [system] [extern_c] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
export *
}
Then under Targets -> Link Binary With Libraries I selected add items and added libz.tbd.
You may want to build at this point.
I was then able to write the following code:
import zlib
public class Zlib {
public class func zlibCompileFlags() -> UInt {
return zlib.zlibCompileFlags()
}
}
You don't have to put the zlib library name in front, except in the above case I named the Swift class func the same as the C function, and without the qualification the Swift func ends up being called repeatedly until the application halts.
Just in case you're as new to XCode as me and want to try the snippets posted in Leandro's answer:
In the case of c++, there is this error that pops up:
"_getInput", referenced from:
You need a c++ header file too. Add c-linkage to your function, then include the header file in the bridge-header:
Swift 3
UserInput.h
#ifndef USERINPUT_H
#define USERINPUT_H
#ifdef __cplusplus
extern "C"{
#endif
getInput(int *output);
#ifdef __cplusplus
}
#endif
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
print(output)
cliinput-Bridging-Header.h
#include "UserInput.h"
Here is the original video explaining this
It appears to be a rather different ball 'o wax when dealing with pointers. Here's what I have so far for calling the C POSIX read
system call:
enum FileReadableStreamError : Error {
case failedOnRead
}
// Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer
// and https://gist.github.com/kirsteins/6d6e96380db677169831
override func readBytes(size:UInt32) throws -> [UInt8]? {
guard let unsafeMutableRawPointer = malloc(Int(size)) else {
return nil
}
let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size))
if numberBytesRead < 0 {
free(unsafeMutableRawPointer)
throw FileReadableStreamError.failedOnRead
}
if numberBytesRead == 0 {
free(unsafeMutableRawPointer)
return nil
}
let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead)
let results = Array<UInt8>(unsafeBufferPointer)
free(unsafeMutableRawPointer)
return results
}
The compiler converts C API to Swift just like it does for Objective-C.
import Cocoa
let frame = CGRect(x: 10, y: 10, width: 100, height: 100)
import Darwin
for _ in 1..10 {
println(rand() % 100)
}
See Interacting with Objective-C APIs in the docs.
Yes, you can of course interact with Apples C libraries. Here is explained how.
Basically, the C types, C pointers, etc are translated into Swift objects, for example a C int
in Swift is a CInt
.
I've build a tiny example, for another question, which can be used as a little explanation, on how to bridge between C and Swift:
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
void getInput(int *output);
Here is the original answer.