NSApplication -runModalSession Crash - PullRequest
       9

NSApplication -runModalSession Crash

0 голосов
/ 16 октября 2018

Я пытаюсь обработать файлы, загруженные пользователем через NSOpenPanel, а затем запустить модальный сеанс, чтобы отобразить прогресс в моем классе пользовательского окна.С первых нескольких десятков попыток он работал хорошо, пока я не столкнулся со случайными сбоями.Все объекты, которые я выделил, освобождались после каждой итерации, поэтому я немного озадачен тем, как действовать дальше.Вот фрагмент кода для потомков:

NSModalSession m = [[NSApplication sharedApplication] beginModalSessionForWindow:progWindow];

while(index < [validImageURLS count])
{
    // Check if user presses the stop track button in pop up window
    if([[NSApplication sharedApplication] runModalSession:m] != NSModalResponseContinue)
    {
        stopProcessing = YES;
        break;
    }

    NSURL* current = [validImageURLS objectAtIndex:index];
    CGImageSourceRef imgSrc = CGImageSourceCreateWithURL((__bridge CFURLRef)current, NULL);
    CGImageRef image = CGImageSourceCreateImageAtIndex(imgSrc, 0, NULL);
    size_t img_width = CGImageGetWidth(image);
    size_t img_height = CGImageGetHeight(image);
    size_t new_size = 0.0;

    if(img_width > img_height)
    {
        new_size = img_width;
    }
    else
    {
        new_size = img_height;
    }

    float aspectRatio = img_width / (float)img_height;

    if(img_width >= img_height)
    {
        img_width  = (int)(round(log2((int)img_width)));
        img_width  = (int)(pow(2.0, img_width));

        if(img_width > 256)
        {
            img_width  = 256;
        }

        img_height = (int)(img_width / aspectRatio);
    }
    else
    {
        img_height = (int)(round(log2((int)img_height)));
        img_height = (int)(pow(2.0, img_height));

        if(img_height > 256)
        {
            img_height = 256;
        }

        img_width  = (int)(img_height * aspectRatio);
    }

    new_size = (int)(round(log2((int)new_size)) + 1);
    new_size = (int)(pow(2.0, new_size));

    GLubyte* imgDataBuffer = new GLubyte[img_width * img_height * ATLAS_NUM_CHANNELS];
    memset(imgDataBuffer, 0, img_width * img_height * ATLAS_NUM_CHANNELS);

    CGColorSpaceRef tmpColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef imgContext = CGBitmapContextCreate(imgDataBuffer,
                                                    img_width,
                                                    img_height,
                                                    8,
                                                    img_width * 4,
                                                    tmpColorSpace,
                                                    kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);

    // Initialize bitmap context attributes
    CGContextSetBlendMode(imgContext, kCGBlendModeNormal);
    CGContextSetInterpolationQuality(imgContext, kCGInterpolationHigh);

    CGRect _c = CGRectMake(0.0, 0.0, img_width, img_height);

    CGContextDrawImage(imgContext, _c, image);

    //flip back
    CGImageRef drawnImg = CGBitmapContextCreateImage(imgContext);

    NSString* c_p = [current path];
    std::string www = std::string([c_p UTF8String]);

    NSString* c_img_name = [current lastPathComponent];
    std::string zzz = std::string([c_img_name UTF8String]);

    // Creating new input content to be put into to the input list
    // for BinPack2D to process later
    SquareContent mycontent(www);
    mycontent.img = drawnImg;

    inputContent += BinPack2D::Content<SquareContent>(mycontent,
                                                      BinPack2D::Coord(),
                                                      BinPack2D::Size((int)img_width, (int)img_height),
                                                      false);

    CGContextRelease(imgContext);
    CGColorSpaceRelease(tmpColorSpace);
    CGImageRelease(image);
    CFRelease(imgSrc);
    delete [] imgDataBuffer;


    // Update progress bar view in our pop up window
    [self UpdateTrackProgressAsync:@[[NSNumber numberWithDouble:index],
                                     [NSNumber numberWithDouble:(int)[validImageURLS count]]]];

    index++;
}

[[NSApplication sharedApplication] endModalSession:m];

Ниже приведен скриншот указанной ошибки:

enter image description here

Я просто следовал заСтруктура, которая была представлена ​​в документации Apple: https://developer.apple.com/documentation/appkit/nsapplication/1428590-runmodalsession?language=objc

Причина, по которой мне нужно запустить это через модальный сеанс для окна вместо отправки кода в фоновой очереди, заключается в том, что я разрабатываю это для плагина.Я хочу, чтобы обработка остановила все остальные интерфейсы в хост-приложении до тех пор, пока работа не будет завершена, или пользователь не нажмет кнопку, которая вызовет вызов stopModal.Я надеюсь, что кто-то может указать мне правильное направление.Спасибо и много ура.

1 Ответ

0 голосов
/ 18 октября 2018

бег с включенными зомби, чтобы сузить причину сбоя.(Изменить схему ... диагностика ... флажок объектов-зомби)

то, что случилось со мной, было то, что endModalSession произошел сбой, когда он вызывается рекурсивно.Не знаю, в чем причина вашей проблемы.

Вот некоторые (возможно, не связанные) проблемы, с которыми я столкнулся:

  • убедитесь, что рекурсия не происходит
  • см. Ниже подфункцию endModalSession, чтобы избежатьрекурсивный вызов
  • убедитесь, что ваше приложение является основным приложением, а окно - ключевым окном

Вот некоторый исходный код FWIW

- (void)endModalSession
{
   if ( modalSession )
   {
      NSModalSession tempSession = modalSession;
      modalSession = NULL;
      [NSApp endModalSession:tempSession];
   }
   appInactiveWait = NO;
}

- (BOOL) waiting { return (modalSession || appInactiveWait); }

- (void)foo
{
   while ( !done )
   {
      // Only start a modal session when app is active.
      // Otherwise you get spurious Dock bouncing when you switch between Finder and this app.
      // Particulary, Remote afp mounts send spurious FSEventStream events every 30 seconds.
      if ( [NSApp isActive] && !startedModal )
      {
         if ( [NSApp keyWindow] == remoteFileManagerWindow || [NSApp keyWindow] == [NSApp mbWindow] )
         {
            startedModal = YES;
            //DLog( @"startingModal (RemoteFileManager) cookie %d", task.readWriteCookie );
            modalSession = [NSApp beginModalSessionForWindow:remoteFileManagerWindow];
            appInactiveWait = NO;
            //DLog( @"startedModal (RemoteFileManager) cookie %d", task.readWriteCookie );
         }
         else
         {
            DLog( @"deferring modal (RemoteFileManager) to keyWindow %@", [NSApp keyWindow] );
         }
      }

      if ( ![self waiting] )
         break;

      if (blah blah blah )
         done = true;

      if ( [self waiting] )
      {             
         if ( modalSession )
         {
            if ([NSApp runModalSession:modalSession] != NSModalResponseContinue)
               break;
         }
         else
         {
            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
         }
      }

      [self processDelayedQueue];
   }
   [self setCurrentTask:nil];

   [self endModalSession];
...