使用NSAutoreleasePool冻结

时间:2011-12-05 22:13:49

标签: objective-c ios4

我正在尝试使用我正在开发的应用来追踪冻结问题。我可能处于NSAutoreleasePool的深层,并且搞砸了。

该应用正在播放midi文件。如果我注释掉下面使用NSAutoreleasePool的“simRespondToFileNote”代码,它就不会冻结。如果我让代码运行,它会在看似随机的点上冻结崩溃日志/控制台输出似乎并不表示问题发生的位置。

以下是程序流程:

  1. 我正在使用Bass midi lib(C lib);它在自己的线程中播放midi文件。

  2. 当发生midi事件时,会触发回调并将midi事件数据包装在NSDictionary中并将其路由到主线程,以便我可以进行UI更新和其他一些操作。

  3. 以下是执行路由的代码:

    - (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实例发送到另一个对象,要么在短暂的延迟后将其排队(使用 performSelector:afterDelay:)。
    2. 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 个答案:

答案 0 :(得分:1)

您正在将midiData对象创建到自动释放池中,使用performSelector作为参数执行延迟midiData,然后耗尽池。你在这里没有看到问题吗?

(释放自动释放池相当于排干它。(阅读文档。)

答案 1 :(得分:1)

simRespondToFileNote:中创建临时自动释放池不是很有用,但不应该是一个问题。您拨打performSelector:withObject:afterDelay:的电话会保留dictionary,直到被叫方为止。如果forwardFileNoteIn:withVelocity:在没有自动释放池的线程上,则可能必须创建它,但通常在方法的顶部执行此操作。如果这个线程已经有了一个池,那就没有理由在这里创建。

根据您的描述,我怀疑simLateResponseToFileNote:阻塞主线程的时间太长。我会在那里寻找瓶颈。