Search code examples
iosmultithreadingplaybacknsthread

NSThread While Loop Based on Boolean - Music Player Start/Stop - IOS


I am trying to create a music player with start/stop functionality. I do this by starting a while loop that loops if a boolean value is true. This while loop is contained in a separate thread. I start this thread in the viewDidLoad method:

[[CoreDataHelper getEditableSong].audioPlayer playOrStopSong];

playOrStopSong looks like this:

- (void) playOrStopSong {
NSLog(@"%d --- before switch", playing);
if (playing) {
    playing = NO;
}
else{
    playing = YES;
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
NSLog(@"%d --- after switch", playing);

}

My run method looks like this (most of it is probably unimportant):

- (void) run {
@autoreleasepool {
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:) userInfo:nil repeats:NO];
    xPlayPosition = 0;
    NSLog(@"thread started!");
    while (playing) {
        NSLog(@"lots of playings -- %d", playing);
        NSMutableDictionary *notesAtCurrentX = [song.noteDict objectForKey:[NSNumber numberWithInt:xPlayPosition]];
        if (notesAtCurrentX != nil) {
            NSString *currentTemplate = [song.soundTemplate objectAtIndex:(NSUInteger) (xPlayPosition/NOTES_PER_TEMPLATE)];
            [self playColumnWithTemplate:currentTemplate andNotesAtCurrentX:notesAtCurrentX andCurrentX:xPlayPosition];
        }
        [NSThread sleepForTimeInterval:30/[song.tempo floatValue]];
        xPlayPosition += 1;
        if (xPlayPosition > [song.length intValue]-1) {
            xPlayPosition = 0;
            [myComposeViewController performSelectorOnMainThread: @selector(animatePlaybackLine) withObject:nil waitUntilDone:NO];
        }
    }
    NSLog(@"thread stopped!");
    [NSThread exit];
}

}

This thread detaches and runs just like it is supposed to. The log prints like so:

0 --- before switch
thread started!
1 --- after switch

And then goes on to print "lots of playings -- 1" a bunch of times.

But when I try to call the playOrStopSong method again, instead of stopping the thread, I just get a new one. The log looks like this:

lots of playings1 -- 1
lots of playings1 -- 1
0 --- before switch
1 --- after switch
thread started!
lots of playings1 -- 1
after click on stop --- 1
lots of playings1 -- 1
lots of playings1 -- 1

It says that it is playing (lots of playings1 -- 1), but then it says that it is not playing (0 --- before switch). This is almost certainly where the problem is. Where did I go wrong? If it helps answer the question, it may be helpful to know that I think that I had this working in an earlier version of my project. (though that seems implausible now...)

Thanks for the help!


Solution

  • What your trace shows is that the old thread never stops, but a new one is started. This would indicate that you're calling playOrStopSong on a newly created (non running) audioPlayer, not the one you actually started earlier.

    I can't see what the life cycle of the audioPlayer is (or is intended to be) from the code in the question, but putting a trace statement inside the initializer of the audioPlayer will most likely show that you're creating a new one when you don't actually intend to.