Swift4 1 swift 和 C 的交互

326 阅读4分钟

C语言基本类型对应表

其中有三个是特殊的

  • wchar_t - CWideChar
  • char16_t - CChar16
  • char32_t - CChar32 其他的都是首字母加上 C 然后采用驼峰式命名方法进行命名

*** ##一、基本类型在Swift中如何引用
  • 1、创建C语言类型
let cInt: CInt = 2
let cChar: CChar = 49

- 2、引用C语言类型
.h
const int global_ten;



.m
const int global_ten = 10;

在Swift中使用

let _ = global_ten

  • 3、NS_STRING_ENUMNS_EXTENSIBLE_STRING_ENUM

NS_STRING_ENUM 通常表示值固定 NS_EXTENSIBLE_STRING_ENUM 表示可扩展

.h
// NS_STRING_ENUM 通常表示值固定
typedef NSString * PQButtonColor NS_STRING_ENUM;

PQButtonColor const PQButtonColorRed;
PQButtonColor const PQButtonColorGreen;
PQButtonColor const PQButtonColorBlue;

// NS_EXTENSIBLE_STRING_ENUM 表示可扩展
typedef int Shape NS_EXTENSIBLE_STRING_ENUM;

Shape const ShapeCircle;
Shape const ShapeTriangle;
Shape const ShapeSquare;



.m

PQButtonColor const PQButtonColorRed = @"Red";
PQButtonColor const PQButtonColorGreen = @"Green";
PQButtonColor const PQButtonColorBlue = @"Blue";



Shape const ShapeCircle = 1;
Shape const ShapeTriangle = 2;
Shape const ShapeSquare = 3; 

使用`NS_STRING_ENUM`修饰的在`swift`中生成一个类型与下面的`struct` 会把前缀忽略掉 ``` struct PQButtonColor: RawRepresentable { typealias RawValue = String
init(rawValue: Self.RawValue)
var rawValue: RawValue { get }

static var red: PQButtonColor { get }
static var green: PQButtonColor { get }
static var blue: PQButtonColor { get }

}


swift

extension PQButtonColor{ static var pink: PQButtonColor { return PQButtonColor(rawValue: "Pink") } }

let bColor: PQButtonColor = .red let bColorString = bColor.rawValue // red

extension Shape { static var ellise: Shape{ return Shape(4) } }

let ellist: Shape = .ellise

两种都可以进行扩展。



<br>
##二、简单方法在Swift中如何引用
***
<br>
- 1、固定参数的方法

定义

int add(int a, int b);

int add(int a, int b){ return a + b; }


使用

//方法 let sumNum = add(30, 30)

let num1 = 20 // 这里必要要转化为CInt类型 let sumNum1 = add(Int32(num1), 2)



- 2、不固定参数的方法

int vsum(int count, va_list numbers); int sum(int count, ...);

int vsum(int count, va_list numbers){ int i = 0, sum = 0; while (i < count) { sum += va_arg(numbers, int); ++i; } return sum; } int sum(int count, ...){ int sum = 0; va_list ap; va_start(ap, count); sum = vsum(count, ap); return sum; }


<br>
使用
>在swift中只能使用`vsum`这个函数,并不可以使用`sum`这个函数,因为其不支持`...`
![没有sum这个方法](https://upload-images.jianshu.io/upload_images/1940927-17d01670e3e22bbe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

<br>

// 使用方法1 需要注意的是 count和数组的元素个数要保持一致 let _ = vsum(7, getVaList([1,2,3,4,56,7,8]))

// 使用方法2 let _ = withVaList([1,2,3]){ vsum(3, $0) }



<br>
##三、简单Struct和union在Swift中如何引用
***
<br>
- 1、`struct`
<br>

定义

typedef struct Location{ int x,y; };

上面代码会在Swift中生成一个struct

struct Location { var x: CInt var y: CInt }


使用

var loc = Location(x: 0, y: 0);



<br>
- 2、为`struct`添加方法

Location moveX(Location loc, int delta); Location moveY(Location loc, int delta);

.m Location moveX(Location loc,int delta){ loc.x += delta; return loc; }

Location moveY(Location loc,int delta){ loc.y += delta; return loc; }


使用

loc = moveY(loc, 5)


但是在`Swift`中是不提倡用这种方式去改变的,应该是用loc.moveX()这样子的方式去调用
如果想达到这种效果,就要是使用`CF_SWIFT_NAME`
以`moveX`为例

// 使用CF_SWIFT_NAME修饰这个方法,把name变成签名 Location moveX(Location loc, int delta) CF_SWIFT_NAME(Location.moveX(self:delta:));


然后就可以在Swift中这样子调用了

loc = loc.moveX(delta: 5)


<br>
通常我还会为struct提供一个工厂方法,在Swift中我们也应该是Location.init去创建,而不是通过一个全局函数去创建

//工厂方法的创建 Location createLocation(int) CF_SWIFT_NAME(Location.init(xy:));

.m

Location createLocation(int xy){ Location loc = { .x = xy, .y = xy }; return loc; }


使用如下:

//工厂方法 let _ = Location(xy: 3)


<br>
接下来在给struct添加一个`getOrigin`和`setOrigin`方法

//getter Location getOrigin(void) CF_SWIFT_NAME(getter:Location.origin()); //setter Location setOrigin(Location) CF_SWIFT_NAME(setter:Location.origin(newOrigin:));

Location origin = { .x = 0, .y = 0 }; Location getOrigin(){ return origin; }

Location setOrigin(Location newOrigin){ origin = newOrigin; return origin; }


使用如下:

// get set Location.origin.y = 10 let _ = Location.origin.x



<br>
###union
由于`Swift`并不支持**union**,所以会在转化的时候变成一个`struct`

比如定义一个如下的 **union**

typedef union { char character; int code; } ASCII;


在Swift中会转化成为

/* struct ASCII{ var character: Int8 var code: CInt

init(character: Int8)
init(code: CInt)

} */


使用如下:

let c = ASCII(character: 77)


然后我们看一个稍微复杂一点点的

// struct and union typedef struct { union { char model; int series; };

struct {
    double pricing;
    bool isAvailable;
}info;

} Car;


使用如下:

let car = Car.init(.init(series: 50), info: .init(pricing: 100, isAvailable: true)) print(car.series)


在匿名的**union**中,可以直接调用里面的变量,就像这个对象不存在一样。


<br>
##三、enum在Swift中如何引用
***
<br>

1、申明一个enum

typedef enum { BMW,AUDI,BENZ }CarType;


使用
<br>

let _ = BMW let _ = AUDI let _ = AUDI


这个和我们想象的有差别,不应该是`CarType.BMW`这样子的形式吗?之所以不是是因为会转化为如下代码

/* struct CarType: RawRepresentable, Equatable {} var BMW: CarType { get } var AUDI: CarType { get } var BENZ: CarType { get } */


如果像变成Swift中的样子,要使用`NS_ENUM(...)`
里面有两个参数:
- 第一个参数是类型
- 第二个是enum名称


定义和使用

typedef NS_ENUM(int,PQCarType) { PQBMW,PQAUDI,PQBENZ };

let bmw: PQCarType = .PQBMW



<br>
***
<br>
##四、指针类型
![image.png](https://upload-images.jianshu.io/upload_images/1940927-546d7ef8b14eec26.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


<br>
- ###[参考资料](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-ID17)
- ###[Demo 地址](https://github.com/codepgq/CAndSwift)