0

我是新手dispatch_queue_t,我的应用程序有两个问题,我认为可以使用 GCD 解决。第一个是在主视图(ViewController)中我有一个由另一个类(AudioViewController)实现的标签,当我在ViewController中进行任何用户交互时,标签停止实现,所以我想如果我使用dispatch_queue_t这个问题会得到解决。

第二件事是,在同一个主视图(ViewController)中,当我按下贡献时,我调用了另一个类(ContributionViewController),而这个类只访问另一个类(AudioViewController)的实例变量,该变量一直在刷新。当我开始贡献时,我创建了一个循环来获得多个值来用它们进行一些微积分,但这些值都是相同的。

我会在这里放一些代码来清除这些东西。

ViewController.m

- (IBAction)makeContribution:(id)sender
{
  NSLog(@"A: Contribution button clicked");
  NSLog(@"-= START CONTRIBUTION =-");
  cvc = [[ContributionViewController alloc] init];
  cvc.avc = self.avc;

  // Get NUM_CONTRIBUTIONS contributions to make average.
  int contContribution;
  for (contContribution = 0; contContribution < NUM_CONTRIBUTIONS; contContribution++) {
        [cvc getEachContribution];
  }

  // Make average
  [cvc makeAverage:NUM_CONTRIBUTIONS];

  [cvc release];
}

AudioViewController.m

- (void)audioInitializationWithTimeInterval:(float)time
{
   NSDictionary* recorderSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                  [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
                                  [NSNumber numberWithInt:44100],AVSampleRateKey,
                                  [NSNumber numberWithInt:1],AVNumberOfChannelsKey,
                                  [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
                                  [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
                                  [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                  nil];
   NSError* error;

   NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];
   recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recorderSettings error:&error];

   //enable measuring
   //tell the recorder to start recording:
   [recorder record];

   if (recorder) {
      [recorder prepareToRecord];
      recorder.meteringEnabled = YES;
      [recorder record];

      levelTimer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(levelTimerCallback:) userInfo:nil repeats:YES];
   }
   else
      NSLog(@"%@",[error description]);
}


- (void)levelTimerCallback:(NSTimer *)timer
{

   //NSLog(@"-= AVC =-");
   [recorder updateMeters];

   db = [recorder averagePowerForChannel:0] - DBOFFSET;
   db += 120;
   db = db < 0 ? 0 : db;

   vc.lab_decibel.text = [NSString stringWithFormat:@"%0.0f", db];
}

ContributionViewController.m

- (void)getEachContribution
{
  actualContribution = self.avc.db;
  NSLog(@"Actual contribution: %f", actualContribution);
  NSLog(@"Sum before: %0.2f", sumContribution);
  sumContribution += actualContribution;
  NSLog(@"Sum After: %0.2f", sumContribution);
}


- (void)makeAverage:(int)numOfContributions
{
  self.average = self.sumContribution / numOfContributions;
  NSLog(@"Average: %0.2f", self.average);
}

所以,主要dispatch_queue_t是要解决我的问题以及如何做到这一点?我试过dispatch_queue_t装上 AudioViewController、ContributionViewController 和 ViewController,但是第一个没有更新标签,第二个崩溃了,第三个标签仍然是 0 值。

感谢您提供解决此问题的任何提示。

编辑 01: 带有 mapView、分贝标签和贡献按钮的 ViewController

分贝标签一直在变化。

4

1 回答 1

0

好的,这开始有意义了。不懂mapView、contribution等语言。这完全是神秘的,但我想我开始理解你的问题了。据我了解,您的问题是为什么您的用户界面没有更新。好的,您的问题的重要答案是,如果您不想,则不需要 GCD。NSTimer做你需要的。

现在,您说您不断更新的数据库字段不再更新。绝对没有理由不继续。我试过了,效果很好。那里有事。就个人而言,当我有一个正在更新我的 UI 的 NSTimer 时,我确保将其关闭viewDidDisappear(如果它不可见,则无需更新您的 UI)并始终将其打开viewDidAppear。当我这样做时,每当我返回带有数据库编号的主视图时,它就会愉快地恢复。或者,如果我想要另一个视图控制器来获取通知,我只需使用委托将其重新打开。

这可能如下所示。

首先,您可能需要一个委托协议:

//  DecibelNotifierDelegate.h

#import <Foundation/Foundation.h>

@protocol DecibelNotifierDelegate <NSObject>

@required

- (void)decibelNotifierUpdate:(CGFloat)db;

@end

然后,你想定义你的 DecibelNotifier 类:

//  DecibelNotifier.h

#import <Foundation/Foundation.h>
#import "DecibelNotifierDelegate.h"

@interface DecibelNotifier : NSObject

@property (nonatomic, retain) id<DecibelNotifierDelegate> delegate;
@property CGFloat db;

- (void)startWithInterval:(float)time target:(id<DecibelNotifierDelegate>)delegate;
- (void)stop;

@end

//  DecibelNotifier.m

#import "DecibelNotifier.h"
#import "AVFoundation/AVFoundation.h"

@interface DecibelNotifier ()
{
    AVAudioRecorder *_recorder;
    NSTimer *_levelTimer;
}
@end

// note, your code makes reference to DBOFFSET and I don't know what that is. Update this following line accordingly.

#define DBOFFSET 0

@implementation DecibelNotifier

@synthesize delegate = _delegate;
@synthesize db = _db;

- (id)init
{
    self = [super init];
    if (self)
    {
        NSDictionary* recorderSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                          [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
                                          [NSNumber numberWithInt:44100],AVSampleRateKey,
                                          [NSNumber numberWithInt:1],AVNumberOfChannelsKey,
                                          [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
                                          [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
                                          [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                          nil];
        NSError* error;

        NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];
        _recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recorderSettings error:&error];

        if (!_recorder)
            NSLog(@"%@",[error description]);
    }

    return self;
}

- (void)startWithInterval:(float)time target:(id<DecibelNotifierDelegate>)delegate
{
    if (_recorder) 
    {
        self.delegate = delegate;

        [_recorder prepareToRecord];
        _recorder.meteringEnabled = YES;
        [_recorder record];

        _levelTimer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(levelTimerCallback:) userInfo:nil repeats:YES];
    }
}

- (void)stop
{
    [_recorder stop];

    [_levelTimer invalidate];
    _levelTimer = nil;

    self.delegate = nil;
}

- (void)levelTimerCallback:(NSTimer *)timer
{
    [_recorder updateMeters];

    CGFloat db = [_recorder averagePowerForChannel:0] - DBOFFSET;
    db += 120;
    db = db < 0 ? 0 : db;

    _db = db;

    [self.delegate decibelNotifierUpdate:db];
}

@end

所以,第一个想要通知的视图控制器可能有一个属性:

@property (strong, nonatomic) DecibelNotifier *dBNotifier;

您可以使用以下方法对其进行初始化:

self.dBNotifier = [[DecibelNotifier alloc] init];

然后,您可以通过以下方式打开通知:

[self.dBNotifier startWithInterval:0.25 target:self];

所以问题是您何时打开和关闭这些通知。我在viewWillAppear和中做viewWillDisappear。您还可以将 dbNotifier 传递给其他视图控制器,它们也可以获得通知。

就像我说的,我试过了,它工作正常,任何想要获取通知的视图控制器都可以打开它并将自己指定为委托,然后你就可以参加比赛了。

于 2012-07-17T07:53:23.350 回答