首页
学习
活动
专区
圈层
工具
发布

读取QR码
EN

Code Review用户
提问于 2015-08-04 16:47:21
回答 1查看 867关注 0票数 -1

我需要完成的是将QR代码与我创建的QR代码匹配。此代码工作正常,但至少需要30秒来验证它是否与我的QR代码匹配。我怎样才能让它更快?

QRCodeVC.h

代码语言:javascript
复制
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface QRCodeVC : UIViewController <AVCaptureMetadataOutputObjectsDelegate> {

NSTimer *timer;
}

@property (weak, nonatomic) IBOutlet UIView *viewPreview;
@property (strong, nonatomic) IBOutlet UIImageView *imageCheckmark;
@property (strong, nonatomic) IBOutlet UILabel *wrongQRCodeLabel;
@property(nonatomic, assign) NSString *messageString;

@end

QRCodeVC.m

代码语言:javascript
复制
#import "QRCodeVC.h"
#import <Parse/Parse.h>

@interface QRCodeVC ()

@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@property (nonatomic) BOOL isReading;

-(BOOL)startReading;
-(void)stopReading;
-(void)loadBeepSound;

@end

@implementation QRCodeVC

- (void)viewDidLoad {
[super viewDidLoad];

timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:@selector(loading) userInfo:nil repeats:YES];

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}

self.imageCheckmark.image = [UIImage imageNamed:@""];

// Initially make the captureSession object nil.
_captureSession = nil;

// Set the initial value of the flag to NO.
_isReading = NO;

// Begin loading the sound effect so to have it ready for playback when it's needed.
[self loadBeepSound];

self.viewPreview.layer.cornerRadius = 20;
self.viewPreview.layer.masksToBounds = YES;
}

- (void) viewWillAppear:(BOOL)animated {


[self.navigationController.navigationBar setHidden:NO];

// Navigation Bar Attibutes
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
[self.navigationController.navigationBar
 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}];
self.navigationController.navigationBar.translucent = NO;

if (!_isReading) {
    // This is the case where the app should read a QR code when the start button is tapped.
    if ([self startReading]) {

    }
}
else{
    // In this case the app is currently reading a QR code and it should stop doing so.
    [self stopReading];
}

// Set to the flag the exact opposite value of the one that currently has.
_isReading = !_isReading;
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

#pragma mark - Private method implementation

- (BOOL)startReading {
NSError *error;

// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video
// as the media type parameter.
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

// Get an instance of the AVCaptureDeviceInput class using the previous device object.
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];

if (!input) {
    // If any error occurs, simply log the description of it and don't continue any more.
    NSLog(@"%@", [error localizedDescription]);
    return NO;
}

// Initialize the captureSession object.
_captureSession = [[AVCaptureSession alloc] init];
// Set the input device on the capture session.
[_captureSession addInput:input];


// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[_captureSession addOutput:captureMetadataOutput];

// Create a new serial dispatch queue.
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("myQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];

// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
[_viewPreview.layer addSublayer:_videoPreviewLayer];


self.messageString = AVMetadataObjectTypeQRCode;

// Start video capture.
[_captureSession startRunning];

return YES;
}


-(void)stopReading{

//    self.imageCheckmark.image = [UIImage imageNamed:@"checkmark_RA"];

// Stop video capture and make the capture session object nil.
[_captureSession stopRunning];
_captureSession = nil;

/*
 // Remove the video preview layer from the viewPreview view's layer.
 [_videoPreviewLayer removeFromSuperlayer];
 */
}


-(void)loadBeepSound{
// Get the path to the beep.mp3 file and convert it to a NSURL object.
NSString *beepFilePath = [[NSBundle mainBundle] pathForResource:@"beep" ofType:@"mp3"];
NSURL *beepURL = [NSURL URLWithString:beepFilePath];

NSError *error;

// Initialize the audio player object using the NSURL object previously set.
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:beepURL error:&error];
if (error) {
    // If the audio player cannot be initialized then log a message.
    NSLog(@"Could not play beep file.");
    NSLog(@"%@", [error localizedDescription]);
}
else{
    // If the audio player was successfully initialized then load it in memory.
    [_audioPlayer prepareToPlay];
}
}


#pragma mark - AVCaptureMetadataOutputObjectsDelegate method implementation

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {








// It is very slow from here





// Check if the metadataObjects array is not nil and it contains at least one object.
if (metadataObjects != nil && [metadataObjects count] > 0) {
    // Get the metadata object.
    AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
    if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {

        NSString *scanResult = [metadataObj stringValue];

        if ([scanResult isEqualToString:@"myQRCode"]) {

            self.imageCheckmark.image = [UIImage imageNamed:@"checkmark_RA"];


            [[PFUser currentUser] incrementKey:@"Points" byAmount:[NSNumber numberWithInt:1]];
            [[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                if (succeeded) {
                    NSLog(@"The object has been saved.");
                } else {
                    NSLog(@"There was a problem");
                }
            }];


             {
            // }

            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Congratulations!" message:@"1 point has been added to your account" delegate:nil cancelButtonTitle:@"Yes!" otherButtonTitles:nil];

            [alertView show];

            NSLog(@"Correct QR Code!");

        } else {

            self.wrongQRCodeLabel.text = @"Wrong QR Code!";
            NSLog(@"Wrong QR Code!");

        }

        NSLog(@"%@", scanResult);






// To here







        // If the found metadata is equal to the QR code metadata then update the status label's text,
        // stop reading and change the bar button item's title and the flag's value.
        // Everything is done on the main thread

        [self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];

        _isReading = NO;

        // If the audio player is not nil, then play the sound effect.
        if (_audioPlayer) {
            [_audioPlayer play];
        }
    }
}
}

- (void) loading {
    }

@end
EN

回答 1

Code Review用户

发布于 2015-08-10 23:12:19

缩进您的代码.

大量的代码对它们几乎没有任何影响。所有的东西都粘在左边的边缘上,这使得区分一个方法的结束和下一个方法的开始是不可能的(一目了然)。

在一组花括号内的所有东西都应该缩进一个级别,比那些大括号外面的东西还要大。

代码语言:javascript
复制
- (void)someMethod {
    if (someCondition) {
        for (Foo *foo in arrayOfFoos) {
            // this is an example of proper indentation
        }
    }
}

不要滥用垂直空格。

垂直空白是一种很好的方法,可以直观地将代码块划分为逻辑上一起的分组。例如,可以将几行声明代码按空行组合在一起。这是一个快速的视觉提示,帮助读者在头脑中组织你的代码。

但任何超过一条空白行的东西几乎都是超杀的。如果您需要特别注意行,请使用注释、多行注释块或您的最佳选择#pragma mark注释。

否则,你只是在锻炼人们的卷轴手指。

不要在代码中留下完全空的方法.

  • (空)装载{}

为什么这个在这里?

任何维护这段代码的人都会问这个问题,考虑到对它缺乏评论,他们会删除它(我目前正在处理一个项目,里面散落着数百个像这样的空方法)。

如果这个空方法需要保留有一个特别好的理由,那么在方法体中留下一个注释(所以它在技术上不再是空的),解释为什么它需要保留。否则,现在就移除它。

如果您不删除或注释它,维护代码的人将删除它。如果我们正在编写好的代码,我们将尽我们所能使维护人员的工作尽可能容易。其中一部分包括删除我们所知道的维护人员逻辑上会删除的内容(或者给维护者留下注释,说明为什么不应该删除它)。

只调用超级的

方法与nothing相同。

  • (DidReceiveMemoryWarning){ 超级接收内存警告;//释放任何可以重新创建的资源。}

如果只调用super,则根本不需要实现该方法。

我意识到这是Xcode在创建视图控制器子类时自动生成的存根代码,但最终,它仍然只是杂乱无章的代码,不管怎么说,好的维护者最终都会删除这些代码,所以现在让我们来解决这个问题。

不要留下注释掉的代码.

您应该使用某种形式的源代码管理。。(提示: Xcode内置了git支持,并将为您创建repos。)这将跟踪您的代码更改,因此,如果您需要回过头来查看项目中的代码,您可以使用源代码管理来实现这一点。

如果需要只为调试生成运行的代码,则可以使用预处理器宏有条件地包含代码:

代码语言:javascript
复制
#if DEBUG
    [self executeSomeDebugModeOnlyMethod];
#endif

如果它不是您只打算为特定构建包含的代码,那么在我讨论留在空方法的麻烦时,您应该出于上述所有原因简单地删除它。最终,它只是看起来像杂乱的维护者,谁可能只是删除它。

不使用UIAlertView.

UIAlertView将在iOS 9中被废弃。UIAlertController是从iOS 8开始引入的。如果您的代码不支持iOS 8,那么应用程序将不会在应用程序商店中获得批准。不支持iOS 9的应用程序的窗口可能会在6个月后关闭。

如果您需要在iOS 8之前支持iOS版本,您需要实现一些条件代码,当它可用时,这些代码应该始终使用UIAlertController,如果没有条件代码,则使用UIAlertView

关于使用文字的

.

通常,除非在初始化稍后要重用的常量时,否则不应该使用文字数字或字符串。

但是,当您使用文字,无论您使用魔术数字或定义值,使用您真正需要的值。

(1.0/2.0)

为什么我们不能写成:

代码语言:javascript
复制
0.5

使用属性。或者不要。

您已经创建了这个属性:

@property (非原子,强) AVAudioPlayer *audioPlayer;

但是,您可以多次直接访问支持变量:

_audioPlayer

而不是通过访问器:

代码语言:javascript
复制
self.audioPlayer

如果要创建属性,请使用访问器。如果不使用访问器,就不要将其创建为属性--只需将其创建为实例变量。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/99024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档