Handle NSItemProvider data types in Share Extension (Swift)

There's a new API that is used in examples, canLoadObject and loadObject

if (itemProvider.canLoadObject(ofClass: UIImage.self)) {
            itemProvider.loadObject(ofClass: UIImage.self, completionHandler: {
                (data, error) in
                print("==== adding image \(image) as note, error=\(error)")
})

https://developer.apple.com/documentation/uikit/drag_and_drop/data_delivery_with_drag_and_drop


As far as I tested, in some cases, you will have a Data in data. So, you may need to write something like this if you do not want to write an Objective-C wrapper for this method:

if attachment.hasItemConformingToTypeIdentifier(IMAGE_TYPE) {
    attachment.loadItem(forTypeIdentifier: IMAGE_TYPE, options: nil) { data, error in
        let myImage: UIImage?
        switch data {
        case let image as UIImage:
            myImage = image
        case let data as Data:
            myImage = UIImage(data: data)
        case let url as URL:
            myImage = UIImage(contentsOfFile: url.path)
        default:
            //There may be other cases...
            print("Unexpected data:", type(of: data))
            myImage = nil
        }
        //...
    }
}

(Not tested, you may need to fix some parts.)


In Objective-C, you can pass an Objective-C block taking (UIImage *item, NSError *error) to the completionHandler of loadItemForTypeIdentifier:options:completionHandler:. In such case, the item provider tries to convert all sorts image data into UIImage.

NSItemProviderCompletionHandler

Discussion

...

item

The item to be loaded. When specifying your block, set the type of this parameter to the specific data type you want. ... The item provider attempts to coerce the data to the class you specify.

So, if you do not mind writing some Objective-C wrapper, you can write something like this:

NSItemProvider+Swift.h:

@import UIKit;

typedef void (^NSItemProviderCompletionHandlerForImage)(UIImage *image, NSError *error);

@interface NSItemProvider(Swift)
- (void)loadImageForTypeIdentifier:(NSString *)typeIdentifier
                          options:(NSDictionary *)options
                completionHandler:(NSItemProviderCompletionHandlerForImage)completionHandler;
@end

NSItemProvider+Swift.m:

#import "NSItemProvider+Swift.h"

@implementation  NSItemProvider(Swift)

- (void)loadImageForTypeIdentifier:(NSString *)typeIdentifier
                           options:(NSDictionary *)options
                 completionHandler:(NSItemProviderCompletionHandlerForImage)completionHandler {
    [self loadItemForTypeIdentifier:typeIdentifier
                            options:options
                  completionHandler:completionHandler];
}

@end

{YourProject}-Bridging-Header.h:

#import "NSItemProvider+Swift.h"

And use it from Swift as:

    if attachment.hasItemConformingToTypeIdentifier(IMAGE_TYPE) {
        attachment.loadImage(forTypeIdentifier: IMAGE_TYPE, options: nil) { myImage, error in
            //...
        }
    }

In my opinion, Apple should provide this sort of type-safe extension of NSItemProvider, you can write a feature request using Apple's Bug Reporter.