I was just trying out iOS's Action Extensions today. When you create one, Xcode inserts a template extension which just shows the image you pass it in.
This sample fails to run. As it turns out, it's due to NSItemProvider (which bridges the data between the processes)'s loadItemForTypeIdentifier method. This method takes a type identifier (e.g. kUTTypeImage) and some options (nil) as input and invokes a supplied completion handler with the object or an error if it can transform the data in to that type. Anyway, it turns out that NSItemProvider, even when invoked with a demo local image from the simulator's Photos app, is returning an NSURL instead of the expected UIImage object.
So let's check the documentation on that completion block - NSItemProviderCompletionHandler. Pasted here for convenience.
A block that receives the item provider’s data.
Declaration
SWIFT
typealias NSItemProviderCompletionHandler = (NSSecureCoding?, NSError!) -> Void
Discussion
Use this block to receive data from a call to the
method. This block takes the following parameters:loadItemForTypeIdentifier:options:completionHandler:
item
The item to be loaded. When specifying your block, set the type of this parameter to the specific data type you want. For example, when requesting text data, you might set the type to
orNSString
. The item provider attempts to coerce the data to the class you specify.NSAttributedString
error
A pointer to an error object for receiving information about any problems that occurred when loading the data.
This may just be really poorly written documentation, but what it seems to suggest is that I'm supposed to specify "UIImage" for the first argument, and it'll do some magic reflection on the block signature and try to make whatever data it holds internally in to a UIImage somehow. It's kind of like a secretly-generic type.
The problem is that I can't do this with Swift. I can't write a block of type (UIImage?, NSError!)->Void and pass it off as a NSItemProviderCompletionHandler.
The sample code people seem to have had that problem, too. It looks like this should have been exported to Swift as a generic function, e.g:
func loadItemForTypeIdentifier<T:NSSecureCoding>(identifier: String, options: [NSObject:AnyObject]?, completionHandler: ((T?, NSError!)->Void)?)
In the sample code's specific case, we can get an NSData from the NSURL and load that in to a UIImage ourselves, but actually one of the major points of this API is to wrap those conversions. There's never any guarantee that it actually does give us a NSURL (that's just what I've seen from the Photos app), so we'll have to cast to make sure that it's an NSURL before doing all of these failable tasks (and what of the other cases? Can it ever just give us a UIImage? Or maybe a raw NSData? We're in undocumented waters here; who can say what'll happen?).