Заморозить с помощью NSAutoreleasePool - PullRequest
0 голосов
/ 06 декабря 2011

Я пытаюсь отследить проблему с зависанием в приложении, которое я разрабатываю.Я могу быть в глубоком конце NSAutoreleasePool и напортачить.

Приложение воспроизводит MIDI-файл.Если я закомментирую приведенный ниже код "simRespondToFileNote" , который использует NSAutoreleasePool, он не зависнет.Если я разрешу запускать код, он будет зависать в кажущихся случайными точках. Выход из журнала сбоев / консоли, похоже, не указывает, где возникает проблема.

Вот поток программы:

  1. Я использую Bass midi lib (C lib);он воспроизводит MIDI-файл в своем собственном потоке.

  2. Когда происходит событие midi, запускается обратный вызов, и я оборачиваю данные события midi в NSDictionary и направляем их в основной поток, чтобы я мог выполнять обновления пользовательского интерфейса и некоторые другие вещи.

Вот код, который выполняет маршрутизацию:

- (void)forwardFileNoteIn:(int) note withVelocity: (int) velocity
{
int position = BASS_ChannelGetPosition(midiFileStream, BASS_POS_MIDI_TICK);
float percent = ((float)position / (float)totalTicks);
int ticksInLoop = outLoopTick - inLoopTick;

QWORD bytes=BASS_ChannelGetPosition(midiFileStream, BASS_POS_BYTE); // get position in bytes
double seconds=BASS_ChannelBytes2Seconds(midiFileStream, bytes); // translate to seconds
int timeStamp =seconds*1000; // translate to milliseconds

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *midiData = [NSDictionary dictionaryWithObjectsAndKeys:
                           @"fileNoteIn", @"eventType",
                          [NSNumber numberWithInt:note], @"note",
                          [NSNumber numberWithInt:velocity],@"velocity",
                          [NSNumber numberWithInt:timeStamp],@"timeStamp",
                          [NSNumber numberWithInt:position],@"position",
                          [NSNumber numberWithFloat:percent],@"percentPlayed",
                          [NSNumber numberWithInt:ticksInLoop],@"ticksInLoop",
                          nil];

[delegate performSelectorOnMainThread:@selector(midiFileEvent:)
                            withObject:midiData
                            waitUntilDone:NO];
[pool release];

} ​​

  1. От делегата сообщение отправляется другому объектуиспользуя экземпляр NSDictionary в качестве параметра.Этот объект либо отправляет экземпляр NSDictionary немедленно другому объекту, либо ставит его в очередь для отправки после небольшой задержки (используя executeSelector: afterDelay: ).

Возможно ли эточто NSAutoreleasePool удаляет экземпляр NSDictionary до запуска сообщения в очереди?Я нигде не сливаю бассейн - я должен это делать?

- (void)simRespondToFileNote:(NSDictionary *)dictionary
{
int velocity = [[dictionary objectForKey:@"velocity"] intValue];

if (velocity == 0){
    // noteOff - send it through
    [delegate routeUserSimMidiEvent:dictionary];
} else {

    float totalPercentCorrect = [dataSource getUserCorrectPercent];

    int note = [[dictionary objectForKey:@"note"] intValue];

    if (totalPercentCorrect < _userAccuracy){

        float lateNoteOnTimeDelay =  (dataSource.postTimeHighAccuracy - (dataSource.postTimeHighAccuracy /4)) / 1000.;
        float lateNoteOffTimeDelay = lateNoteOnTimeDelay + .1; // revise

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        // create noteOff data w/ velocity == 0; timeStamp == 0;
        NSDictionary *midiData = [NSDictionary dictionaryWithObjectsAndKeys:
                                  [NSNumber numberWithInt:note], @"note",
                                  [NSNumber numberWithInt:0],@"velocity",
                                  [NSNumber numberWithUnsignedInt:0],@"timeStamp",
                                  nil];

        [self performSelector:@selector(simLateResponseToFileNote:)  withObject:dictionary afterDelay: lateNoteOnTimeDelay];
        [self performSelector:@selector(simLateResponseToFileNote:)  withObject:midiData afterDelay: lateNoteOffTimeDelay];
        [pool release];

    } else {

        float lateNoteOnTimeDelay =  (dataSource.postTimeLowAccuracy + (dataSource.postTimeLowAccuracy /4)) / 1000.0;
        float lateNoteOffTimeDelay = lateNoteOnTimeDelay + .1; // revise
         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        // create noteOff data w/ velocity == 0; timeStamp == 0;
        NSDictionary *midiData =[NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithInt:note], @"note",
                                 [NSNumber numberWithInt:0],@"velocity",
                                 nil];

        // queue late noteOn
        [self performSelector:@selector(simLateResponseToFileNote:)  withObject:dictionary afterDelay: lateNoteOnTimeDelay];
        // queue late noteOff
        [self performSelector:@selector(simLateResponseToFileNote:)  withObject:midiData afterDelay: lateNoteOffTimeDelay];
        [pool release];

    }
}

}

Ответы [ 2 ]

1 голос
/ 06 декабря 2011

Создание временного пула автоматического выпуска в simRespondToFileNote: не очень полезно, но не должно быть проблемой.Ваш звонок на performSelector:withObject:afterDelay: будет удерживать dictionary до тех пор, пока он не будет вызван.Если forwardFileNoteIn:withVelocity: находится в потоке, который еще не имеет пула автоматического выпуска, вам, возможно, придется его создать, но обычно вы делаете это в начале метода.Если у этого потока уже есть пул, здесь нет причин для его создания.

Из вашего описания я бы заподозрил, что simLateResponseToFileNote: слишком долго блокирует основной поток.Я бы нашел там узкое место.

1 голос
/ 06 декабря 2011

Вы создаете свой midiData объект в пуле с автоматическим выпуском, выполняете отложенное performSelector, используя midiData в качестве параметра, затем сливаете пул. Вы не видите здесь проблемы?

(Освобождение пула автоматического выпуска эквивалентно его сливу. (Прочтите документацию.))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...