Mac Catalyst UIActivity subclasses that implement the activityViewController property don't work. API is broken.

I have a UIActivity subclass that generates data asynchronously. So as an example say we have a "Generate Spreadsheet" activity. In the implementation of the activity:

-(UIViewController*)activityViewController

{
    if (_backingViewController == nil)
    {
        _backingViewController = [[ActivityWithProgressUIViewController alloc]init];
        [self performActivity]; // <-- start the activity...  always required to manually start the activity when providing a view controller.

    }
    return _backingViewController;

}// return non-nil to have view controller presented modally. call activityDidFinish at end. default returns nil

Then in -performActivity override...do the work...

-(void)performActivity

{
    NSLog(@"start performing...pretend we are creating a spreadsheet..");

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        [self activityDidFinish:YES];
        NSLog(@"Finished performing.");
    });

}

And that works on iOS. On Mac Catalyst the system never dismisses the view controller returned by UIActivity subclass. Also the UIActivityViewController's completionWithItemsHandler is called immediately after the custom activity is invoked, the system doesn't wait for the custom activity to call -activityDidFinish: The system just leaves the abandoned view controller returned by the custom activity on screen.

Works fine on iOS. Easy to reproduce in a sample project.

I filed FB11878213. I can't catch a break with this framework...

According to the documentation:

https://developer.apple.com/documentation/uikit/uiactivity?language=objc

the system will start the activity either via activityViewController or performActivity. You can override one or the other, but it doesn't seem right for you to be invoking performActivity in the body of the if. Do you have a reason for thinking it needs to invoked "manually" there?

Thanks a lot for the reply. The reason why I invoke -performActivity manually is because I just choose to use this method as the place to "start" the work but it is not at all related to the reported issue. My implementation never calls super and the system does not call -performActivity on an activity that returns an activityViewController. You can rename the -performActivity method in the sample project to any method name you want but the issue will still occur:

-(void)_doStartActivityWork

{
    NSLog(@"start performing...");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self activityDidFinish:YES];
        NSLog(@"Finished performing.");
    });

}

Hmm, well, this might be a good candidate for a DTS support incident to investigate:

https://developer.apple.com/account#CodeLevelSupportCard

I don't think I want to burn a TSI on this since I have a workaround though all the available workarounds using public API are not great.

On Catalyst you have to manually dismiss the UIActivity's activityViewController property in -activityDidFinish: since the popover holding the UIActivityViewController immediately dismisses after you click the application activity.

Also an extra strong reference to the custom UIActivity is required otherwise it gets released with the UIActivityViewController before it has a chance to finish and the abandoned view controller remains in the UI.

Another option is to just not use a popover with UIActivityViewController but that isn't Mac like.

Mac Catalyst UIActivity subclasses that implement the activityViewController property don't work. API is broken.
 
 
Q