0

In my project I'm using WSAssetPickerController.

Despite the toolbar not working (not a huge issue), everything is working fine.

I have added a share button in the view controller, but I can't seem to get the UIDocumentInteractionController to get called, I tried copying the same method I'm using for files saved in the apps folder (which works fine). But here it's not.

How the irrelevant Downloads page works:

NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Downloads"];
path = [path stringByAppendingPathComponent:fileName];

documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
[documentController setDelegate:self];
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];

How the images get loaded:

#pragma mark - Fetching Code

    - (void)fetchAssets
    {
        // TODO: Listen to ALAssetsLibrary changes in order to update the library if it changes. 
        // (e.g. if user closes, opens Photos and deletes/takes a photo, we'll get out of range/other error when they come back.
        // IDEA: Perhaps the best solution, since this is a modal controller, is to close the modal controller.

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            [self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {

                if (!result || index == NSNotFound) {

                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.tableView reloadData];
                        self.navigationItem.title = [NSString stringWithFormat:@"%@", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]];
                    });

                    return;
                }

                WSAssetWrapper *assetWrapper = [[WSAssetWrapper alloc] initWithAsset:result];

                dispatch_async(dispatch_get_main_queue(), ^{

                    [self.fetchedAssets addObject:assetWrapper];

                });

            }];
        });

        [self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.5];
    }

How I load and call the button:

- (void)viewDidLoad
{
    self.navigationItem.title = @"Loading";

    UIBarButtonItem *shareButton = [[UIBarButtonItem alloc]
                                    initWithBarButtonSystemItem:UIBarButtonSystemItemAction
                                    target:self
                                    action:@selector(shareAction:)];
    self.navigationItem.rightBarButtonItem = shareButton;
    self.navigationItem.rightBarButtonItem.enabled = NO;


    // TableView configuration.
    self.tableView.contentInset = TABLEVIEW_INSETS;
    self.tableView.separatorColor = [UIColor clearColor];
    self.tableView.allowsSelection = NO;


    // Fetch the assets.
    [self fetchAssets];
}

Should and did select fetched assets

#pragma mark - WSAssetsTableViewCellDelegate Methods

- (BOOL)assetsTableViewCell:(WSAssetsTableViewCell *)cell shouldSelectAssetAtColumn:(NSUInteger)column
{
    BOOL shouldSelectAsset = (self.assetPickerState.selectionLimit == 0 ||
                              (self.assetPickerState.selectedCount < self.assetPickerState.selectionLimit));

    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;

    WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];

    if ((shouldSelectAsset == NO) && (assetWrapper.isSelected == NO))
        self.assetPickerState.state = WSAssetPickerStateSelectionLimitReached;
    else
        self.assetPickerState.state = WSAssetPickerStatePickingAssets;

    return shouldSelectAsset;
}

- (void)assetsTableViewCell:(WSAssetsTableViewCell *)cell didSelectAsset:(BOOL)selected atColumn:(NSUInteger)column
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    // Calculate the index of the corresponding asset.
    NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;

    WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
    assetWrapper.selected = selected;

    // Update the state object's selectedAssets.
    [self.assetPickerState changeSelectionState:selected forAsset:assetWrapper.asset];

    // Update navigation bar with selected count and limit variables 
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.assetPickerState.selectionLimit) {
            self.navigationItem.title = [NSString stringWithFormat:@"%@ (%lu/%ld)", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName], (unsigned long)self.assetPickerState.selectedCount, (long)self.assetPickerState.selectionLimit];
        }
    });

    if (self.assetPickerState.selectedCount == 0) {
        self.navigationItem.rightBarButtonItem.enabled = NO;
    }
    else {
        self.navigationItem.rightBarButtonItem.enabled = YES;
    }

}

Work needed to below with example from the download code I have used before.

-(void)shareAction:(id)sender {

        //Launch UIDocumentInteractionController for selected images

        documentController =[[UIDocumentInteractionController alloc]init];
        documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath://Code needed here??//]];
        documentController.delegate=self;
        [documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}

What would be the best practice to do this?

Thanks.

UPDATE 8/4:

-(void)shareAction:(id)sender {

        //Launch UIDocumentInteractionController for selected images
    if (self.assetPickerState.selectedCount >= 1) {


        documentController = [[UIDocumentInteractionController alloc] init];
        documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:@"public.image"]];
        [documentController setDelegate:self];
        [documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];

    }

}
Returns: Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.)
ChrisOSX
  • 724
  • 2
  • 11
  • 28

1 Answers1

0

Your interactionControllerWithURL: doesn't seem to be a problem but I have observed that -presentOpenInMenuFromRect: does not show if there are no apps that can open the file.

If your purpose is to share the file, and generally that doesn't mean open the file in the conventional sense, then instead of:
-presentOpenInMenuFromRect:inView:animated:
use
-presentOptionsMenuFromRect:inView:animated:

The former is an OpenInMenu and latter is an OptionsMenu.
For the tiny difference, check my related answer or check Apple doc directly


Example:

//this seems fine
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];

//do this
[documentController presentOptionsMenuFromRect:CGRectZero 
                                        inView:self.view
                                      animated:YES];

Also..., just before you present the documentInteractionController, it's good practice to specify the file's UTI so the documentInteractionController can populate itself with the appropriate options that can be performed & the list of all apps that can handle this file:

Example:

//assuming the file is a PDF
[documentController setUTI:@"com.adobe.pdf"];

//or... same thing but a more standardized way would be
[documentController setUTI:(NSString *)kUTTypePDF];
//but for this second style you'll need to add the `MobileCoreServices` framework
//to your project bundle and specify the following in your .h or .m
//#import <MobileCoreServices/MobileCoreServices.h>

Extra: Apple's Uniform Type Identifiers Reference

Community
  • 1
  • 1
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • Ill give that a try when i get home. But the thing is that it isn't a specific file. Its the selected asset that's being selected. I.e the images from the ohoti library that you helped in my last question. – ChrisOSX Aug 04 '14 at 20:06
  • @ChrisOSX : sure, no issues. anyways... for images, you can use `@"public.image"` as the UTI instead. Also, for clarity purpose, `NSLog` the `path` variable and specify that in your question. – staticVoidMan Aug 04 '14 at 20:14
  • I get the error: The operation couldn’t be completed. (Cocoa error 260.) when I use the updated code shown in question. – ChrisOSX Aug 04 '14 at 23:19
  • 1
    @ChrisOSX : good sign but now the `URL` is incorrect. **you have** `[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:@"public.image"]];` but **you need** `[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:[NSURL fileURLWithPath:path]]];` – staticVoidMan Aug 05 '14 at 04:57
  • @ChrisOSX : **Note:** `@"public.image"` is the `UTI` and never the `URL`. I hope I didn't confuse you unnecessarily. – staticVoidMan Aug 05 '14 at 05:00
  • No you didn't confuse me :) The only confusing part right now is trying to define the path to the images in the photos library. – ChrisOSX Aug 05 '14 at 12:18
  • @ChrisOSX : hm.. alright, then... `NSLog` `path` after `path = [path stringByAppendingPathComponent:fileName];` and add path string to your question. – staticVoidMan Aug 05 '14 at 13:02