2014-12-07 1 views
1

API SocketScan для iOS написан в Objective-C и предназначен для интеграции сканеров SocketMobile в режиме CHS в собственные приложения.Swift Delegates и 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 на «удаленный» вид. Конечно, это представление также обозначается как scanApiHelperDelegate и содержит все необходимые функции. Однако это не работает. Первоначальный viewController по-прежнему является делегатом, а штрих-код сканирования продолжает запускать функции, перечисленные в исходном viewController, а не в текущем. Компилятор не возвращает ошибок.

Я подозреваю, что это либо a) что-то о том, как Swift взаимодействует с API Objective-C, либо b) я неправильно объявляю, какой должен быть новый делегат scanApi, используя «self».

Итак, как правильно объявить новый делегат scanApi в этом сценарии или это проблема с API?

ответ

1

Текущая версия 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