Swift委托和SocketScan scanApi.setDelegate()

问题描述:

iOS的SocketScan API是用Objective-C编写的,目的是将SocketMobile扫描器以CHS模式集成到本机应用程序中。Swift委托和SocketScan scanApi.setDelegate()

当启动ScanApi时,需要将ViewController设置为ScanApiHelperDelegate,它需要对viewDidLoad进行一些设置以及从扫描仪接收操作的一些功能。

瓦尔是设置:

var scanApi = ScanApiHelper() 
var scanApiConsumer = NSTimer() 

然后在viewDidLoad中,下面的代码实现:

scanApi.setDelegate(self) 
scanApi.open() 
scanApiConsumer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector:Selector("onTimer"), userInfo: nil, repeats: true) 

接着,下面的功能是通过scanApiConsumer称为侦听来自扫描仪的通知:

func onTimer() -> Void{ 
    scanApi.doScanApiReceive() 
    scanApi.getDevicesList() 
} 

当扫描条码时,它会执行以下操作ng:

func onDecodedData(device: DeviceInfo, decodedData: ISktScanDecodedData) { 
    //code to execute here 
} 

如果需要,用户将被路由到另一个视图,其中扫描条形码会执行不同的代码。 scanApi.setDelegate设置如下:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if segue.identifier == "manifestToRepackContainer" { 
     let vc = (segue.destinationViewController as RepackContainer) 
     scanApi.setDelegate(vc) 
     vc.containerBarcode = GlobalVars.barcodeData 
    } 
} 

这也很棒。一旦你在那里,扫描仪正确执行指定的功能。而且,在viewDidAppear对原有观众,我有这样的设置,这也按预期工作:

override func viewDidAppear(animated: Bool) { 
    scanApi.setDelegate(self) 
} 

当用户需要在故事板的一个完全不同的领域扫描功能产生的问题是(在“远程”视图),其中一个prepareForSegue方法是不可能触发一个scanApi.setDelegate()

我最初的想法是简单地定义scanApi委托在“远程”视图通过执行scanApi.setDelegate(self)在viewDidAppear on “远程”视图。当然,这个视图也被指定为scanApiHelperDelegate并包含所有需要的功能。但是,它不起作用。原始viewController仍然是代理,扫描条形码继续触发原始viewController中列出的功能,而不是当前的功能。编译器不返回错误。

我怀疑它是a)Swift与Objective-C API交互的方式或b)我错误地声明了应该使用“self”的新scanApi委托。

那么,在这种情况下声明新的scanApi委托的正确方法是什么?或者这是API的问题?

ScanApiHelper的当前版本不支持多个委托视图,但将来的版本将会。以下是我们所做的修改,如果您想将其添加到项目中的ScanApiHelper。

注:变化是向后兼容的,所以你可以放心地应用这些改变或升级到ScanApiHelper的最新版本推出时,即使你并不需要支持多个代表意见

ScanApiHelper。ħ

Index: ScanApiHelper.h 
=================================================================== 
--- ScanApiHelper.h (revision 12778) 
+++ ScanApiHelper.h (revision 12779) 
@@ -65,6 +65,7 @@ 
@end 

@protocol ScanApiHelperDelegate <NSObject> 
[email protected] 
/** 
    * called each time a device connects to the host 
    * @param result contains the result of the connection 
@@ -103,7 +104,6 @@ 
    */ 
-(void) onErrorRetrievingScanObject:(SKTRESULT) result; 

[email protected] 
/** 
    * called each time ScanAPI receives decoded data from scanner 
    * @param result is ESKT_NOERROR when decodedData contains actual 
@@ -179,9 +179,15 @@ 
    id<ISktScanApi>_scanApi; 
    id<ISktScanObject>_scanObjectReceived; 
    NSObject* _commandContextsLock; 
+ BOOL _shared;// to indicate when ScanApiHelper is shared across multiple views 
+ NSMutableArray* _delegateStack; 
} 

++(ScanApiHelper*)sharedScanApiHelper; 

+-(void)pushDelegate:(id<ScanApiHelperDelegate>)delegate; 
+-(void)popDelegate:(id<ScanApiHelperDelegate>)delegate; 
+ 
/** 
    * register for notifications in order to receive notifications such as 
    * "Device Arrival", "Device Removal", "Decoded Data"...etc... 

ScanApiHelper.mm

Index: ScanApiHelper.mm 
=================================================================== 
--- ScanApiHelper.mm (revision 12778) 
+++ ScanApiHelper.mm (revision 12779) 
@@ -105,12 +105,16 @@ 
@implementation ScanApiHelper 

-(id)init{ 
+ static ScanApiHelper* sharedScanApiHelper=nil; 
    self=[super init]; 
    if(self!=nil){ 
+  sharedScanApiHelper=self; 
     _commandContextsLock=[[NSObject alloc]init]; 
     _deviceInfoList=[[NSMutableDictionary alloc]init]; 
     _scanApiOpen=FALSE; 
     _scanApiTerminated=TRUE;// by default ScanApi is not started 
+  _shared=NO; 
+  _delegateStack=[[NSMutableArray alloc]init]; 
    } 
    return self; 
} 
@@ -130,6 +134,7 @@ 
    _commandContextsLock=nil; 

    _deviceInfoList=nil; 
+ _delegateStack=nil; 
} 
#else 
-(void)dealloc{ 
@@ -151,10 +156,54 @@ 

    [_deviceInfoList release]; 
    _deviceInfoList=nil; 
+  
+ [_delegateStack release]; 
+ _delegateStack=nil; 
+  
    [super dealloc]; 
} 
#endif 

++(ScanApiHelper*)sharedScanApiHelper{ 
+ static ScanApiHelper* scanApiHelper=nil; 
+ if(scanApiHelper==nil){ 
+  scanApiHelper=[[ScanApiHelper alloc]init]; 
+  scanApiHelper->_shared=YES; 
+ } 
+ return scanApiHelper; 
+} 
+ 
+-(void)pushDelegate:(id<ScanApiHelperDelegate>)delegate{ 
+ if(_delegate != delegate){ 
+  if(_delegate!=nil){ 
+   [_delegateStack addObject:_delegate]; 
+  } 
+  _delegate=delegate; 
+  [self generateDeviceArrivals]; 
+ } 
+} 
+ 
+-(void)popDelegate:(id<ScanApiHelperDelegate>)delegate{ 
+ if(_delegate ==delegate){ 
+  if(_delegateStack.count>0){ 
+   id<ScanApiHelperDelegate> newDelegate=[_delegateStack objectAtIndex:_delegateStack.count-1]; 
+   [_delegateStack removeLastObject]; 
+   _delegate = newDelegate; 
+   // generate a device Arrival for each scanner we've already receive 
+   // so that the new view can be aware of the connected scanners 
+   if(_delegate!=nil){ 
+    for (NSString* key in _deviceInfoList) { 
+     DeviceInfo* device=[_deviceInfoList objectForKey:key]; 
+     [_delegate onDeviceArrival:ESKT_NOERROR device:device]; 
+    } 
+   } 
+  } 
+  else{ 
+   _delegate=nil; 
+  } 
+ } 
+} 
+ 
/** 
    * register for notifications in order to receive notifications such as 
    * "Device Arrival", "Device Removal", "Decoded Data"...etc... 
@@ -1519,14 +1568,15 @@ 
#endif  
    // release the previous ScanAPI object instance if 
    // it exists 
- if(_scanApi!=nil){ 
-  [_scanApi close]; 
-  [SktClassFactory releaseScanApiInstance:_scanApi]; 
- } 
    _scanApi=[SktClassFactory createScanApiInstance]; 
    SKTRESULT result=[_scanApi open:nil]; 
- if(_delegate!=nil) 
-  [_delegate onScanApiInitializeComplete:result]; 
+ if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onScanApiInitializeComplete:)])){ 
+  [_delegate onScanApiInitializeComplete:result]; 
+ } 
    _scanApiTerminated=FALSE; 

#if __has_feature(objc_arc) 
@@ -1576,8 +1626,9 @@ 
      } 
     } 
     else{ 
-   if(_delegate!=nil) 
+   if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onErrorRetrievingScanObject:)])){ 
       [_delegate onErrorRetrievingScanObject:result]; 
+   } 
     } 
    } 
    return result; 
@@ -1600,8 +1651,9 @@ 
      result=[self handleDeviceRemoval:scanObj]; 
      break; 
     case kSktScanMsgIdTerminate: 
-   if(_delegate!=nil) 
+   if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onScanApiTerminated)])){ 
       [_delegate onScanApiTerminated]; 
+   } 
      closeScanApi=TRUE; 
      break; 
     case kSktScanMsgSetComplete: 
@@ -1619,8 +1671,9 @@ 

    // if there is an error then report it to the ScanAPIHelper user 
    if(!SKTSUCCESS(result)){ 
-  if(_delegate!=nil) 
+  if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onError:)])){ 
      [_delegate onError:result]; 
+  } 
    } 
    return closeScanApi; 
} 
@@ -1657,8 +1710,9 @@ 
    } 

    // notify the ScanApiHelper user a scanner has connected to this host 
- if(_delegate!=nil) 
+ if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onDeviceArrival:device:)])){ 
     [_delegate onDeviceArrival:result device:deviceInfo]; 
+ } 

#if __has_feature(objc_arc) 
#else 
@@ -1702,8 +1756,9 @@ 
    [SktClassFactory releaseDeviceInstance:scanDevice]; 

    // notify the ScanApiHelper user a scanner has connected to this host 
- if(_delegate!=nil) 
+ if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onDeviceRemoval:)])){ 
     [_delegate onDeviceRemoval:deviceInfo]; 
+ } 

    return result; 
} 
@@ -1766,7 +1821,7 @@ 
      result=[self handleDecodedData:scanObj]; 
      break; 
     case kSktScanEventError: 
-   if(_delegate!=nil) 
+   if((_delegate!=nil)&&([_delegate respondsToSelector:@selector(onError:)])) 
       [_delegate onError:[[scanObj Msg]Result]]; 
      break; 

@@ -1809,6 +1864,7 @@ 
    return result; 
} 

/** 
    * sendNextCommand 
    * 
@@ -1855,4 +1911,25 @@ 
    return result; 
} 

+/** 
+ * generateDeviceArrivals 
+ * 
+ * internal function to generate device 
+ * arrival notifications when the delegate 
+ * change to a new delegate. 
+ * This is used in a multi views application 
+ * that has more than one view to receive the 
+ * decoded data 
+ */ 
+-(void)generateDeviceArrivals{ 
+ // generate a device Arrival for each scanner we've already receive 
+ // so that the new view can be aware of the connected scanners 
+ if(_delegate!=nil){ 
+  for (NSString* key in _deviceInfoList) { 
+   DeviceInfo* device=[_deviceInfoList objectForKey:key]; 
+   [_delegate onDeviceArrival:ESKT_NOERROR device:device]; 
+  } 
+ } 
+} 
+ 
@end