El Capitan - NSProgressIndicator doesn't show

I have an OS X Swift app which works correctly in Yosemite, but the progress bar doesn't show in El Capitan. All else works normally in the "real" program.


I created a stub program to try to debug the problem, but I still can't get the progress bar to show. Using XCode 7.0.1 (7A1001) and created this from scratch


The test app takes a counter input (typed in) and should show a progress bar until count is reached. If the progress bar is unhidden it does appear, but doesn't refresh until the end, when it shows blue 100%. I've added progressBar.display() - no effect. same with window.display() no change.

progCount is another field I put on the window to see if I could see the numbers ticking up, but that didn't show until the last number.

I used debug and saw the i value ticking up, and progressBar.doubleValue also incremented. It looks like a window redraw issue but I can't find what to do differently. Remember too, this works on Yosemite.


Any help would be welcome, thanks


--- code fragment ----

@IBOutlet weak var window: NSWindow!

@IBOutlet weak var progressBar: NSProgressIndicator!

@IBOutlet weak var counter: NSTextField!

@IBOutlet weak var progCount: NSTextField!

(a bit of housekeeping not shown)

@IBAction func countUp (sender: NSButton) {

var i=0

if counter.integerValue != 0 {

progressBar.hidden = false

progressBar.minValue = 0.0

progressBar.doubleValue = 0.0

progressBar.maxValue = counter.doubleValue

while i < counter.integerValue {

i=i+1

progressBar.incrementBy(1.0)

progCount.doubleValue = progressBar.doubleValue

}

progressBar.hidden = true

}

}

--- end ---

Replies

Hi,


I have observed a similar behaviour in an Objective-C program that I implemented years ago.


I do a [NSWindow display] to make sure, the window is really redrawn, but it just is not redrawn. I tried an old version I compiled long ago and a new one. The result is the same: on El Capitan the window is not updated on Yosemite it is.


So I think we have to wait and see if Apple comes up with a fix on this in 10.11.1. Has anybody installed the beta with a similar problem?


As you have isolated your problem in a small program I think you should open up a radar jsut to make sure they work on it.

I have a similar problem too in my Objective-C app. Any leads?

We have an application (actually, a DLL that runs within Apple's Installer application) and it has used aNSProgressIndicator (progress bar) successfully for years in prior versions of OSX. But with 10.11.1, the progress bar does not update on the GUI. The bar appears, at 0%, and just stays at 0% even tho we are updating the progress programatically. Our update code is:


IBOutlet NSProgressIndicator* progressIndicator;

for ( ...) {

[progressIndicator setDoubleValue:value];

[progressIndicator displayIfNeeded];

}


and this code has been working for many years. The "value" is increasing in our software .. and in fact if we click on the Installer GUI frame: the progress bar does update to the correct value (somewhere between 0% and 100%). Plus: the debugger shows that internally we are advancing "value" from 0 to 100.


But El Capitan is not updating the progress bar on the GUI. Do we need to add some sort of GUI flush call inside the for loop? Any ideas?

Update: Installed OSX 10.11.2 (beta 3) - still does not work: The progress bar is not updated on the GUI, even tho the software is calling setDoubleValue().


The progress bar GUI _does_ do an isolated update when the user changes focus from the application Window to another application. But that is the only way to get the progress bar to update.


And I should point out that the logic above that is updating the progress bar is running in its own thread ... not the main GUI thread. So the tight for loop that is doing work should not be blocking GUI updates. As I said: this logic has worked for many years in prior versions of OSX.

Same issue here. Progress indicator is broken.


Had fairly simple code in one app, where a set amount of items are loaded, and I increment the progress one by one in a loop on the main thread, which blocks the GUI until progress is finished. I was able to workaround this, by moving the loop to a background queue, and updating the progress on the main queue. I then had to go through the trouble to ensure I disabled GUI elements while displaying progress, because the UI was no longer blocking since the loop was moved on a background queue. I filed a bug on this awhile ago.

I finally arrived at a workaround by eliminating the NSProgressIndicator and replacing it with a NSLevelIndicatorCell. The appearance is slightly different (the ends are not rounded) but at least it works.


To recap: My NSProgressIndicator worked fine for many years in prior versions of OSX, but stopped working in El Capitan (the bar would not update/refresh as my application updated the bar's value). The update logic (that called setDoubleValue) has always been, as required, in a background thread, so that is not the problem. And displayIfNeeded was always correctly called. The only unique thing about this is that it is a DLL plugin for the Apple Installer application ... that is, it is not its own application. But I cannot see why that would be signficant. After many hours of experiments and trials, I was never able to get the NSProgressIndicator to update in this Installer plugin scenario.


So the final solution was to abandon the NSProgressIndicator and shift to a NSLevelIndicatorCell (an NSSlider may also be an acceptable workaround). Why does the level indicator work where the progress bar does not? I suppose because the level indicator is an NSControl whereas the progress bar is an NSView. Not sure why NSControl is updated in Installer plugins, but NSView is not.

I heard back from Apple on my bug report. They said this behavior is intended and the soluton is to wrap incrementBy: inside a NSAnimationContext animation group. I'm not sure if this is documented anywhere and def. was a change made in El Capitan.


It seems to work. Only did a little bit of testing with it though.

Hello,


any pointers on how to do that? I'm new to xcode and trying to solve this issue in a software of ours.

Yeah, NSAnimationContext has a factory method with a couple of blocks. The first block you wrap animations in, the second block gets called on completion. Usually, you use it like this.


[NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context)
    {
        context.duration = 0.5;
        [aView.animator setFrameOrigin:NSMakePoint(newOriginPoint.x, newOriginPoint.y)];
    }
    completionHandler:^{
        NSLog(@"Complete!");
    }];


This makes animations very easy. Prior to 10.11 using one wasn't required to get progress indicators to update...though you often had to give it a kick in the teeth with a displayIfNeeded message.

Try to tick the tick box "Can draw concurrent", that solved it for me!


It might not be the real solution and might break in the future, but atleast it's a work around

Thanks for relaying the solution. Here is what worked for me:


[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.0];
[myProgressIndicator setDoubleValue : myCurrentValue ];
[myProgressIndicator displayIfNeeded];
[NSAnimationContext endGrouping];


I had to add the two lines at top, and one at bottom. I did not need runAnimationGroup. My progress bar is determinate (grows larger from left to right).

I tried all of those suggestions but I can't get any to work with my deteminate progress indicator (which worked fine up until El Capitan - oh why did I upgrade). Perhaps Apple can update the documentation on the NSProgressIndicator to actually describe what is needed to make it work, since none of the above suggestions such as using an NSAnimationContext grouping are mentioned.

Found myself in the same situation because I was updating my NSProgressIndicator from a tight loop on the main thread.

Prior to El Capitan I was just calling displayIfNeeded on the window the progress indicator was in and it worked fine. With El Capitan this broke and the progress indicator was stuck at 0%.

While I agree that rewriting my loop to run on a background thread and call into the main thread to update the progress indicator would be the best solution, in my case this unfortunately wasn't an option.


So the workaround I came up with is to first call displayIfNeeded on the window, followed by

[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]];


This gives the main runloop some time to breath and the progress indicator advances properly.

I have applied your workaround and I confirm that it can solve similar situations also in macOS Sierra:


github.com/gui-dos/Guigna/blob/d5e3ed7174e8881ee6899f1a0c6995a971f71b3b/Legacy/Guigna-Swift/Guigna/GuignaAppDelegate.swift#L87-L101

That worked - thanks a lot!! even with just [NSDate date]