5 Replies
      Latest reply on Nov 30, 2019 11:13 AM by PBK
      sitedude2019 Level 1 Level 1 (0 points)

        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