虽然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用到的头文件添加进去:
#import "native_lib.h"
参考Dynamsoft Barcode SDK的在线代码示例做一些修改:
#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;
}
修改下生成的头文件:
#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 *:
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结果:
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中创建按钮和文本控件:
@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!
创建按钮响应函数:
@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 加载文件:
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用于读取条形码:
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条形码应用:

源码
https://github.com/yushulx/swift-barcode-reader
来源:oschina
链接:https://my.oschina.net/u/1187419/blog/496784