虽然Objective-C还活的很好,但是苹果已经把重心转移到Swift上。未来Mac和iOS的开发必然是以Swift为主。因为Swift还比较新,很多SDK还没有提供Swift版本。这里分享下如何使用Swift来调用C。
参考原文:How to Bridge C Code to Create Swift Barcode Reader on Mac
作者:Xiao Ling
翻译:yushulx
软件下载
混合使用Swift和C
苹果在iBooks里提供了电子书Using Swift with Cocoa and Objective-C。在网页上可以阅读Interacting with C APIs。
Swift和C类型映射关系参考:
使用Swift和C在Mac上实现1D/2D条形码应用
在Xcode中使用快捷键Command+Shift+N创建新工程。
头文件和依赖的库直接拖入工程就行了。Xcode会自动关联。
Command+N创建一个C文件,用于调用底层的C动态链接库(Dynamsoft Barcode dylib)。
完成之后,Xcode会弹出提示:
确认之后,Xcode会自动生成一个桥接头文件。把C用到的头文件添加进去:
1
|
#import "native_lib.h"
|
参考Dynamsoft Barcode SDK的在线代码示例做一些修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#include "native_lib.h"
int
dbr_release_memory(pBarcodeResultArray paryResult)
{
DBR_FreeBarcodeResults(&paryResult);
printf
(
"Game Over\n"
);
return
0;
}
pBarcodeResultArray dbr_decodeBarcodeFile(
char
* pszImageFile)
{
// Parse command
__int64
llFormat = (OneD |QR_CODE);
int
iMaxCount = 0x7FFFFFFF;
int
iIndex = 0;
ReaderOptions ro = {0};
pBarcodeResultArray paryResult = NULL;
int
iRet = -1;
char
* pszTemp = NULL;
char
* pszTemp1 = NULL;
struct
timeval begin, end;
if
(NULL == pszImageFile)
{
printf
(
"The syntax of the command is incorrect.\n"
);
return
NULL;
}
// Set license
DBR_InitLicense(
"A825E753D10C6CAC7C661140EC5ABEC3"
);
// Read barcode
gettimeofday(&begin, NULL);
ro.llBarcodeFormat = llFormat;
ro.iMaxBarcodesNumPerPage = iMaxCount;
iRet = DBR_DecodeFile(pszImageFile, &ro, &paryResult);
gettimeofday(&end, NULL);
// Output barcode result
pszTemp = (
char
*)
malloc
(4096);
if
(iRet != DBR_OK)
{
sprintf
(pszTemp,
"Failed to read barcode: %s\r\n"
, DBR_GetErrorString(iRet));
printf
(
"%s"
, pszTemp);
free
(pszTemp);
return
NULL;
}
if
(paryResult->iBarcodeCount == 0)
{
sprintf
(pszTemp,
"No barcode found. Total time spent: %.3f seconds.\r\n"
,
((
float
)((end.tv_sec * 1000 * 1000 + end.tv_usec) - (begin.tv_sec * 1000 * 1000 + begin.tv_usec))/(1000 * 1000)));
printf
(
"%s"
, pszTemp);
DBR_FreeBarcodeResults(&paryResult);
return
0;
}
sprintf
(pszTemp,
"Total barcode(s) found: %d. Total time spent: %.3f seconds\r\n\r\n"
, paryResult->iBarcodeCount,
((
float
)((end.tv_sec * 1000 * 1000 + end.tv_usec) - (begin.tv_sec * 1000 * 1000 + begin.tv_usec))/(1000 * 1000)));
printf
(
"%s"
, pszTemp);
return
paryResult;
}
|
修改下生成的头文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#ifndef __DBRConsole__native_lib__
#define __DBRConsole__native_lib__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "If_DBR.h"
pBarcodeResultArray dbr_decodeBarcodeFile(
char
* fileName);
int
dbr_release_memory(pBarcodeResultArray paryResult);
const
char
* GetFormatStr(
__int64
format);
#endif /* defined(__DBRConsole__native_lib__) */
|
用Swift编写命令行工具
把Swift中的String转换成char *:
1
2
3
4
5
|
var file: String =
"/Applications/Dynamsoft/Barcode Reader 3.0 Trial/Images/AllSupportedBarcodeTypes.tif"
// barcode file
//let namePtr = strdup(filePath.bridgeToObjectiveC().UTF8String)
var filePtr = strdup(file.cStringUsingEncoding(NSUTF8StringEncoding)!)
var fileName: UnsafeMutablePointer<CChar> = UnsafeMutablePointer(filePtr)
|
注释掉的接口bridgeToObjectiveC 在早期的Swift版本中是可以用的。Xcode 6.4中已经去掉了。
命令行获取Barcode结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var result : pBarcodeResultArray = dbr_decodeBarcodeFile(fileName)
free
(filePtr)
println(
"Total barcode: \(String(result.move().iBarcodeCount))\n......."
)
var count = result.move().iBarcodeCount
var pBarcodeResult: pBarcodeResult = nil
var barcodeIndex = 1
// print barcode recognition results
for
i in 0..<Int(count) {
pBarcodeResult = result.move().ppBarcodes.advancedBy(i).move()
println(
"Barcode: \(barcodeIndex++)"
)
println(
"Page: \(String(pBarcodeResult.move().iPageNum))"
)
var lFormat:
__int64
= pBarcodeResult.move().llFormat
var format = String.fromCString(GetFormatStr(lFormat))
println(
"Type: \(format!)"
)
println(
"Value: \(String.fromCString(pBarcodeResult.move().pBarcodeData)!)"
)
println(
"......."
)
}
// free C memory
dbr_release_memory(result)
|
用Swift创建Cocoa应用
在AppDelegate.swift中创建按钮和文本控件:
1
2
3
4
5
|
@IBOutlet weak var window: NSWindow!
@IBOutlet weak var btLoad: NSButton!
@IBOutlet weak var btRead: NSButton!
@IBOutlet weak var text: NSTextField!
@IBOutlet weak var filePath: NSTextField!
|
创建按钮响应函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@IBAction func onClick(sender: NSButton) {
var title = sender.title
switch
(title) {
case
"Load Barcode File"
:
dispatch_async(dispatch_get_main_queue()) {
self.openPanel()
}
break
case
"Read Barcode"
:
if
self.filePath.stringValue ==
""
{
text.stringValue =
"Please add image path!"
return
}
println(
"default:"
+ self.filePath.stringValue)
var dbr = DBR()
text.stringValue = dbr.decodeFile(self.filePath.stringValue)!
break
default
:
break
}
}
|
在Interface Builder中把代码和UI元素关联起来:
使用NSOpenPanel 加载文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
func openPanel() {
var openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection =
false
openPanel.canChooseDirectories =
false
openPanel.canCreateDirectories =
false
openPanel.canChooseFiles =
true
openPanel.beginWithCompletionHandler { (result) -> Void in
if
result == NSFileHandlingPanelOKButton {
if
let path = openPanel.URL?.path {
self.filePath.stringValue = path
}
}
}
}
|
创建DBR.swift用于读取条形码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
import Foundation
class
DBR {
func decodeFile(file: String)->String? {
var filePtr = strdup(file.cStringUsingEncoding(NSUTF8StringEncoding)!)
var fileName: UnsafeMutablePointer<CChar> = UnsafeMutablePointer(filePtr)
var result : pBarcodeResultArray = dbr_decodeBarcodeFile(fileName)
free
(filePtr)
println(
"Total barcode: \(String(result.move().iBarcodeCount))\n......."
)
var count = result.move().iBarcodeCount
var barcodeIndex = 1
var results: String =
""
// print barcode recognition results
for
i in 0..<Int(count) {
var pBarcodeResult = result.move().ppBarcodes.advancedBy(i).move()
results +=
"Barcode: \(barcodeIndex++)\n"
results +=
"Page: \(String(pBarcodeResult.move().iPageNum))\n"
var lFormat:
__int64
= pBarcodeResult.move().llFormat
var format = String.fromCString(GetFormatStr(lFormat))
results +=
"Type: \(format!)\n"
results +=
"Value: \(String.fromCString(pBarcodeResult.move().pBarcodeData)!)\n"
results +=
".......\n"
}
// free C memory
dbr_release_memory(result)
return
results
}
}
|
运行1D/2D条形码应用: