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!
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With