Search code examples
iosobjective-cnsdictionarynstimer

Iterating through an NSDictionary and timing events in IOS


I'm new to IOS / Objective C and am trying to figure out the best way to create a collection, iterate over it, and time events.

I have a series of lines of a song and I want an individual line of a song to appear on the screen as the music is playing at the right point in the song. So I've started by doing the following: I put the individual lines into a Dictionary and the millisecond value of when the line should appear.

   NSDictionary *bualadhBos = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithInt:2875], @"Muid uilig ag bualadh bos, ",
                             [NSNumber numberWithInt:3407], @"Muid uilig ag tógáil cos, ",
                             [NSNumber numberWithInt:3889], @"Muid ag déanamh fead ghlaice, ",
                             [NSNumber numberWithInt:4401], @"Muid uilig ag geaibíneacht. ",
                             [NSNumber numberWithInt:4900], @"Buail do ghlúine 1, 2, 3, ",
                             [NSNumber numberWithInt:5383], @"Buail do bholg mór buí, ",
                             [NSNumber numberWithInt:5910], @"Léim suas, ansin suigh síos, ",
                             [NSNumber numberWithInt:6435], @"Seasaigh suas go hard arís. ",
                             [NSNumber numberWithInt:6942], @"Sín amach do dhá lamh, ",
                             [NSNumber numberWithInt:7430], @"Anois lig ort go bhfuil tú ' snámh. ",
                             [NSNumber numberWithInt:7934], @"Amharc ar dheis, ansin ar chlé, ",
                             [NSNumber numberWithInt:8436], @"Tóg do shúile go dtí an spéir. ",
                             [NSNumber numberWithInt:8940], @"Tiontaigh thart is thart arís, ",
                             [NSNumber numberWithInt:9436], @"Cuir síos do dhá lámh le do thaobh, ",
                             [NSNumber numberWithInt:9942], @"Lámha suas is lúb do ghlúin, ",
                             [NSNumber numberWithInt:10456], @"Suigí síos anois go ciúin. ", nil
                             ];

then I wanted to iterate over the Dictionary, create a Timer that would call a method that is responsible for changing the text in the textLayer

for (id key in bualadhBos ) {
    NSTimer *timer;
    timer = [[NSTimer scheduledTimerWithTimeInterval:bualadhBos[key] target:self selector:@selector(changeText) userInfo:nil repeats:NO]];

}

-(void)changeText {
    // change the text of the textLayer
    textLayer.string = @"Some New Text";
}

But as I started to debug this and inspect how it might work, I noticed in the debugger that the order which the items appear in the Dictionary have all been shuffled around. I'm also concerned (I don't know enough about this) that I'm creating multiple timers and that there might be a more efficient approach to solving this problem.

Any direction would be greatly appreciated.


Solution

  • Dictionaries are sorted by definition in the way that is most suitable for hash algorithm so you should never rely on their order.

    In your case it would be better to build a binary tree and have a single NSTimer that fires once a second, performs binary tree search and returns the closest string for provided time offset.

    If you use AVFoundation or AVPlayer for playback. Then to synchronize subtitles with media playback, you could use something like addPeriodicTimeObserverForInterval to fire timer once a second and perform search in your binary tree and update UI.

    In pseudo code:

    [player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
        // get playback time
        NSTimeInterval seconds = CMTimeGetSeconds(time);
    
        // search b-tree
        NSString* subtitle = MyBtreeFindSubtitleForTimeInterval(seconds);
    
        // update UI
        myTextLabel.text = subtitle;
    }];