如何在Mac上使用Swift调用C接口开发条形码应用

虽然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条形码应用:

源码

https://github.com/yushulx/swift-barcode-reader

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值