Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle NSItemProvider data types in Share Extension (Swift)

I have an issue with Share Extension programming in Swift (3).
My main problem is with the handling of the data type of a NSItemProvider.
Here's the issue: depending on the App that I launch my Extension from, I get a different type of data. For example:
I tell the application:

let IMAGE_TYPE = kUTTypeImage as String
if attachment.hasItemConformingToTypeIdentifier(IMAGE_TYPE){
     attachment.loadItem(forTypeIdentifier: IMAGE_TYPE, options: nil){ data, error in
     ...
}

(Note: attachment is of type NSItemProvider)

When executed from the Photos App, data is a URL so I create a UIImage from that and continue with that.
The problem is, that for some applications data already is a UIImage and I can't find how to do the case differentiation.
Best would probably be to check the data type of the data object but it's not trivial to me at least.
Thanks in advance for any help!

like image 704
unixb0y Avatar asked Mar 04 '17 01:03

unixb0y


2 Answers

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.

like image 164
OOPer Avatar answered Oct 18 '22 18:10

OOPer


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

like image 5
Phuah Yee Keat Avatar answered Oct 18 '22 20:10

Phuah Yee Keat