简体   繁体   中英

Dispatch_queue issue

I'm new using dispatch_queue_t and I have two problems with my app which I think that could be solved using GCD. The first one is that in the main view (ViewController) I have a label which is actualized by another class (AudioViewController), and when I do any user interaction in ViewController the label stop to actualize, so I think if I use dispatch_queue_t this problem will be solved.

The second thing is that in the same main view (ViewController) when I press a contribution I call another class (ContributionViewController) and this class accesses just a instance variable of another class (AudioViewController) which is refreshed all the time. When I start contribution, I made a loop to get more than one value to make some calculus with them and those values are all the same though.

I'll put some code here trying to clear the things.

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);
}

So, the main thing is dispatch_queue_t is going to solve my problems and how to do that? I've tried to put dispatch_queue_t on AudioViewController, ContributionViewController and ViewController, but the first didn't update the label, the second crashed and the third one the label still with 0 value.

Thanks for any tips to solve this problem.

EDIT 01: 带有mapView,分贝标签和贡献按钮的ViewController

The decibel label changes all the time.

Ok, this is starting to make sense. I didn't understand the mapView, contribution, etc. language. It was entirely cryptic, but I think I'm starting to understand your question. As I understand it, your question is why your user interface is not being updated. Ok, the big answer to your question is that you don't need GCD if you don't want to. The NSTimer does what you need.

Now, you say that your continuously updated db field is no longer updated. There's absolutely no reason why it shouldn't continue. I've tried it, and it works fine. There's something going on there. Personally, when I've got a NSTimer that is updating my UI, I make sure to turn it off in viewDidDisappear (no point in updating your UI if it's not visible) and always turn it on in viewDidAppear . When I did this, whenever I returned to my main view with the db numbers, it happily resumed. Or if I wanted another view controller to get the notifications, I just turned it back on using a delegate.

That might look like the following.

First, you probably want a delegate protocol:

//  DecibelNotifierDelegate.h

#import <Foundation/Foundation.h>

@protocol DecibelNotifierDelegate <NSObject>

@required

- (void)decibelNotifierUpdate:(CGFloat)db;

@end

And then, you want to define your DecibelNotifier class:

//  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

and

//  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

So, the first view controller that wants the notifications might have a property:

@property (strong, nonatomic) DecibelNotifier *dBNotifier;

You can initialize it with:

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

You can then turn on notifications with:

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

So the question is when you turn these notifications on and off. I do it in viewWillAppear and viewWillDisappear . You can also pass the dbNotifier to other view controllers and they can get notifications, too.

Like I said, I tried this out and it works fine, with any view controller that wants to get notifications can just turn it on and specify itself as the delegate, and you're off to the races.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM