UIActivityItemProvider.item should be optional

Recently in the UIKit framework

UIActivityItemProvider
's
item
property was declared as
nonnull
.

The problem is that the actual item may not be available at this time and the app has no way to abort the process.


Let's take a photo app for example which allows sharing photos:

  1. An empty
    UIImage
    is used as placeholder item to indicate that the app can share an image.
  2. Once the user selects an activity, the app tries to download the fullsize image before returning it from
    UIActivityItemProvider
    's
    item
    property.
  3. The download may fail in which case the app is unable to continue since item expects a non-nil return value.
  4. The app could either crash or return some garbage
    UIImage
    which iOS would then share with the destination app.


How are we supposed to implement the

item
property in cases where the retrieval of the item can fail?

I known this post is super old, but I just wanted to comment that I've filed a radar suggesting that the

item
property be made nullable: openradar.me/radar?id=4563896690016256


Please file your own bug report if you agree!

Hi,


since UIActivityItemProvider inherits from NSOperation maybe sending a cancel message to self will do the trick. (Just a wild guess).


Dirk

Unfortunately that won't work.

We start loading the data when the `item` getter is called and from there we have to return something - no matter if the op was cancelled or not.


My current workaround is to return an instance of an empty dummy class no one cares about.

I ended up figuring out a pretty good workaround for this. While UIActivityItemProvider includes a bunch of its own functionality, it still very much implements the UIActivityItemSource protocol. I knew that. What I hadn't considered is that this means I can just override

activityViewController:itemForActivityType:
and return
nil
there when it's appropriate.


So the last line of my

item
method now looks like this:


return self.placeholderItem;


You could also return

[NSNull null]
here, or really any object. I chose the placeholderItem because it seems a little safer—at the very least I know it's returning an object of the expected type, in case anything about the implementation ever changes.

Then all I have to do is add my own implementation of

activityViewController:itemForActivityType:
(where we are allowed to return nil):


- (nullable id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType {
     id item = [super activityViewController:activityViewController itemForActivityType:activityType];
     if ([item isEqual:self.placeholderItem]) return nil;
     return item;
}


Just call super to get the item, return nil if it's something you don't want to include, or return the item if it is. Note that if your

placeholderItem
might ever be equal to something you actually dowant to share, you will need to change this implementation a bit—but the same basic concept should work.
UIActivityItemProvider.item should be optional
 
 
Q