Posts

Post marked as solved
5 Replies
1.9k Views
Hi everyone. I was am new to coding using Xcode. I wrote an app in Android studio and I was porting it over to iOS. I have the app working but I am not very happy with the reading speed of barcodes. I was hoping someone could suggest what I can do to speed up reading.Here is my code, thank you guys so much.#import "ScanViewController.h" #import "Utils.h" #import "LoginToken.h" #import #import #define COLOR_SUCCESS [UIColor colorWithDisplayP3Red:44.0f/255.0f green:1.0f blue:0 alpha:1.0f] #define COLOR_ERROR [UIColor colorWithDisplayP3Red:1.0f green:0 blue:0 alpha:1.0f] @interface ScanViewController () @property (nonatomic, readwrite) AVCaptureSession *captureSession; @property (nonatomic, readwrite) AVCaptureVideoPreviewLayer *videoPreviewLayer; @property (nonatomic, readwrite) UIView *qrCodeFrameView; @property (nonatomic, readwrite) UILabel *qrCodeTextView; @property (nonatomic, readwrite) NSArray *supportedCodeTypes; @property (nonatomic, readwrite) long long lastScanTime; @property (nonatomic, readwrite) NSString *lastScanCode; @property (nonatomic, readwrite) AVAudioPlayer *audioPlayer; @end @implementation ScanViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.captureSession = [AVCaptureSession new]; self.captureSession.sessionPreset = AVCaptureSessionPresetHigh; self.supportedCodeTypes = @[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code]; // AVMetadataObjectTypeCode39Code, // AVMetadataObjectTypeCode39Mod43Code, // AVMetadataObjectTypeCode93Code, // AVMetadataObjectTypeCode128Code, // AVMetadataObjectTypeAztecCode, // AVMetadataObjectTypePDF417Code, // AVMetadataObjectTypeITF14Code, // AVMetadataObjectTypeDataMatrixCode, // AVMetadataObjectTypeInterleaved2of5Code, // AVMetadataObjectTypeQRCode]; self.lastScanTime = 0; AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if(captureDevice == nil) { NSLog(@"Failed to get the camera device"); return; } @try { // Get an instance of the AVCaptureDeviceInput class using the previous device object. AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil]; // Set the input device on the capture session. [self.captureSession addInput:input]; // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init]; [self.captureSession addOutput:captureMetadataOutput]; // Set delegate and use the default dispatch queue to execute the call back [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; captureMetadataOutput.metadataObjectTypes = self.supportedCodeTypes; // captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] } @catch (NSException *error) { // If any error occurs, simply print it out and don't continue any more. NSLog(@"%@", error); return; } // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer. self.videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession]; self.videoPreviewLayer.videoGravity = kCAGravityResizeAspectFill; self.videoPreviewLayer.frame = self.view.layer.bounds; [self.view.layer addSublayer:self.videoPreviewLayer]; // Start video capture. [self.captureSession startRunning]; // Move the result view and loading view to the front [self.view bringSubviewToFront:self.resultView]; [self.view bringSubviewToFront:self.loadingView]; // Initialize QR Code Frame to highlight the QR code self.qrCodeFrameView = [[UIView alloc] init]; if (self.qrCodeFrameView) { self.qrCodeFrameView.layer.borderColor = UIColor.greenColor.CGColor; self.qrCodeFrameView.layer.borderWidth = 2; [self.view addSubview:self.qrCodeFrameView]; [self.view bringSubviewToFront:self.qrCodeFrameView]; } self.qrCodeTextView = [[UILabel alloc] init]; if (self.qrCodeTextView) { [self.qrCodeTextView setTextColor:UIColor.greenColor]; [self.qrCodeTextView setFont:[UIFont systemFontOfSize:20]]; [self.qrCodeFrameView addSubview:self.qrCodeTextView]; } [self rotateLoadingImage]; [self setResultType:RESULT_TYPE_WORKING codeContent:@"Ready" price:0.00]; [self.loadingView setHidden:YES]; } -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"notification" ofType:@"wav"]; NSURL *soundFileUrl = [NSURL fileURLWithPath:soundFilePath]; self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileUrl error:nil]; // Check if valid verified login exists LoginToken *token = [LoginToken getInstance]; [token load]; -(void)viewWillDisappear:(BOOL)animated { if (self.audioPlayer != nil) { [self.audioPlayer stop]; self.audioPlayer = nil; } [super viewWillDisappear:animated]; } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ -(void) updatePreviewLayer:(AVCaptureConnection*)layer orientation:(AVCaptureVideoOrientation)orientation { layer.videoOrientation = orientation; self.videoPreviewLayer.frame = self.view.bounds; } -(void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if(self.videoPreviewLayer.connection != nil) { UIDevice *currentDevice = [UIDevice currentDevice]; UIDeviceOrientation orientation = [currentDevice orientation]; AVCaptureConnection *previewLayerConnection = self.videoPreviewLayer.connection; if(previewLayerConnection.isVideoOrientationSupported) { switch (orientation) { case UIDeviceOrientationPortrait: [self updatePreviewLayer:previewLayerConnection orientation:AVCaptureVideoOrientationPortrait]; break; case UIDeviceOrientationLandscapeRight: [self updatePreviewLayer:previewLayerConnection orientation:AVCaptureVideoOrientationLandscapeLeft]; break; case UIDeviceOrientationLandscapeLeft: [self updatePreviewLayer:previewLayerConnection orientation:AVCaptureVideoOrientationLandscapeRight]; break; case UIDeviceOrientationPortraitUpsideDown: [self updatePreviewLayer:previewLayerConnection orientation:AVCaptureVideoOrientationPortraitUpsideDown]; break; default: [self updatePreviewLayer:previewLayerConnection orientation:AVCaptureVideoOrientationPortrait]; break; } } } } -(void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection { // Check if the metadataObjects array is not nil and it contains at least one object. if (metadataObjects.count == 0) { self.qrCodeFrameView.frame = CGRectZero; return; } // Get the metadata object. AVMetadataMachineReadableCodeObject *metadataObj = (AVMetadataMachineReadableCodeObject*)(metadataObjects[0]); if ([self.supportedCodeTypes containsObject:metadataObj.type]) { // If the found metadata is equal to the QR code metadata (or barcode) then update the status label's text and set the bounds AVMetadataObject *barCodeObject = [self.videoPreviewLayer transformedMetadataObjectForMetadataObject:metadataObj]; NSString *code = metadataObj.stringValue; if (code != nil) { // check upc a code if ([self checkUpcACode:metadataObj.type code:code] == NO) { self.qrCodeTextView.text = @""; return; } int i=0; for (i=0; i<code.length; i++)="" {<br=""> char ch = [code characterAtIndex:i]; if (ch != '0') break; } if (i>0) i--; code = [code substringFromIndex:i]; self.qrCodeFrameView.frame = barCodeObject.bounds; [self.qrCodeTextView setText:code]; self.qrCodeTextView.frame = CGRectMake(0, self.qrCodeFrameView.frame.size.height-20, self.qrCodeFrameView.frame.size.width, 20); NSLog(@"%@", code); [self handleBarcode:code]; } else { self.qrCodeTextView.text = @""; } } } -(BOOL)checkUpcACode:(AVMetadataObjectType)type code:(NSString*)code { if (type == AVMetadataObjectTypeEAN13Code) { if ([code hasPrefix:@"0"] && [code length] > 0) { return YES; } } return NO; } -(void)handleBarcode:(NSString*)code { // check duration for scan long long timeSinceLastScan = [Utils currentMilliTime] - self.lastScanTime; if (timeSinceLastScan < 1000 * 10 && [code isEqualToString:self.lastScanCode]) { return; } NSLog(@"time since last scan : %lld", timeSinceLastScan); self.lastScanTime = [Utils currentMilliTime]; self.lastScanCode = [NSString stringWithFormat:@"%@", code]; long long nCode = [code longLongValue]; if (nCode > 0) { [self setResultType:RESULT_TYPE_WORKING codeContent:@"Working" price:0.00]; [self.mApi getPrice:nCode handler:^(bool ok, long long code, double value) { dispatch_async(dispatch_get_main_queue(), ^{ [self handlePriceResult:ok code:code price:value]; }); }]; } else { [self handleScanFeedback:RESULT_TYPE_ERROR]; [self setResultType:RESULT_TYPE_ERROR codeContent:@"Failed to parse code" price:0.00]; } } -(void)rotateLoadingImage { [UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ [self.loadingImageView setTransform:CGAffineTransformMakeRotation(M_PI)]; } completion:^(BOOL finished){ [self rotateLoadingImageAgain]; }]; } -(void)rotateLoadingImageAgain { [UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ [self.loadingImageView setTransform:CGAffineTransformMakeRotation(M_PI * 2)]; } completion:^(BOOL finished){ [self rotateLoadingImage]; }]; } -(void)setResultType:(ResultType)type codeContent:(NSString*)codeContent price:(double)price { switch (type) { case RESULT_TYPE_DEFAULT: { [self.loadingView setHidden:YES]; [self.resultView setBackgroundColor:[UIColor whiteColor]]; [self.resultCodeDisplay setText:@"Ready"]; [self.resultPriceDisplay setText:@"$ 0.00"]; [self.resultIconDisplay setImage:[UIImage imageNamed:@"ic_default_24dp"]]; break; } case RESULT_TYPE_NOT_FOUND: { [self.loadingView setHidden:YES]; [self.resultView setBackgroundColor:[UIColor whiteColor]]; [self.resultCodeDisplay setText:[NSString stringWithFormat:@"%@ - not found try rescanning", codeContent]]; [self.resultPriceDisplay setText:@"$ 0.00"]; [self.resultIconDisplay setImage:[UIImage imageNamed:@"ic_not_found_24dp"]]; break; } case RESULT_TYPE_SUCCESS_NORMAL: { [self.loadingView setHidden:YES]; [self.resultView setBackgroundColor:[UIColor whiteColor]]; [self.resultCodeDisplay setText:codeContent]; [self.resultPriceDisplay setText:[NSString stringWithFormat:@"$ %.02f", price]]; [self.resultIconDisplay setImage:[UIImage imageNamed:@"ic_default_24dp"]]; break; } case RESULT_TYPE_SUCCESS_TARGET: { [self.loadingView setHidden:YES]; [self.resultView setBackgroundColor:COLOR_SUCCESS]; [self.resultCodeDisplay setText:codeContent]; [self.resultPriceDisplay setText:[NSString stringWithFormat:@"$ %.02f", price]]; [self.resultIconDisplay setImage:[UIImage imageNamed:@"ic_success_24dp"]]; break; } case RESULT_TYPE_ERROR: { [self.loadingView setHidden:YES]; [self.resultView setBackgroundColor:COLOR_ERROR]; [self.resultCodeDisplay setText:@"Error"]; [self.resultPriceDisplay setText:@"$ 0.00"]; [self.resultIconDisplay setImage:[UIImage imageNamed:@"ic_error_black_24dp"]]; break; } case RESULT_TYPE_WORKING: { [self.loadingView setHidden:NO]; break; } default: break; } } -(void)handleScanFeedback:(ResultType)type { switch (type) { case RESULT_TYPE_SUCCES break; } } S_TARGET: { if (self.audioPlayer != nil) [self.audioPlayer play]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); break; } case RESULT_TYPE_SUCCESS_NORMAL: case RESULT_TYPE_ERROR: case RESULT_TYPE_NOT_FOUND: { AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); break; } default: @end
Posted Last updated
.