iOS UIActivityViewController using UIActivityItemProvider “forgets” items

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-24 12:30:16

问题


I have a larger app that should be able to share multiple images. I implemented this using UIActivityViewController and UIActivityItemProvider to have asynchronous usage of the items (so that i only have to prepare one image at a time and not have to fill the memory with all of them at once to share them).

I was "inspired" by the Apple Airdrop example: AirdropSample download

However when using my app to share e.g. 9 images (to camera Roll == "Save 9 images") only 4 to 7 images end up being in the camera roll, no error messages whatsoever. If i repeat it over and over sometimes i get 5 images or 6 seemingly random.

I cannot post my app here, but i modified the above sample in a way that it will also randomly "fail" with delivering all images to the camera Roll...

If you download above sample and replace 4 files with these, it shows the problem:

APLAsyncImageViewController.h:

#import <UIKit/UIKit.h>
#import "APLAsyncImageActivityItemProvider.h"

@interface APLAsyncImageViewController : UIViewController
@end

APLAsyncImageViewController.m:

#import "APLAsyncImageViewController.h"
#import "APLProgressAlertViewController.h"

NSString * const kProgressAlertViewControllerIdentifier = @"APLProgressAlertViewController";


@interface APLAsyncImageViewController ()

@property (strong, nonatomic) UIWindow *alertWindow;
@property (strong, nonatomic) APLProgressAlertViewController *alertViewController;
@property (strong, nonatomic) UIPopoverController *activityPopover;

@property (weak, nonatomic) IBOutlet UIButton *shareImageButton;

- (IBAction)openActivitySheet:(id)sender;

@end


@implementation APLAsyncImageViewController


- (IBAction)openActivitySheet:(id)sender
{
    NSMutableArray *itemArray = [[NSMutableArray alloc] init];
    for( int i = 0; i < 9;i++)
    {
        APLAsyncImageActivityItemProvider *aiImageItemProvider = [[APLAsyncImageActivityItemProvider alloc] init];
        [itemArray addObject: aiImageItemProvider];
    }

    //Create an activity view controller with the activity provider item. UIActivityItemProvider (AsyncImageActivityItemProvider's superclass) conforms to the UIActivityItemSource protocol
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:itemArray applicationActivities:nil];

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        //iPhone, present activity view controller as is
        [self presentViewController:activityViewController animated:YES completion:nil];
    }
    else
    {
        //iPad, present the view controller inside a popover
        if (![self.activityPopover isPopoverVisible]) {
            self.activityPopover = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
            [self.activityPopover presentPopoverFromRect:[self.shareImageButton frame] inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
        }
        else
        {
            //Dismiss if the button is tapped while pop over is visible
            [self.activityPopover dismissPopoverAnimated:YES];
        }
    }
}
@end

APLAsyncImageActivityItemProvider.h:

#import <UIKit/UIKit.h>
@interface APLAsyncImageActivityItemProvider : UIActivityItemProvider
@end

APLAsyncImageActivityItemProvider.m:

#import "APLAsyncImageActivityItemProvider.h"
#import "UIImage+Resize.h"

@implementation APLAsyncImageActivityItemProvider


- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
    return [[UIImage alloc] init];
}

- (id)item
{
    UIImage *image = [UIImage imageNamed:@"Flower.png"];

    //CGSize imageSize;
    //imageSize.height = 1000;
    //imageSize.width = 1000;
    //image = [UIImage imageWithImage:image scaledToFitToSize:imageSize];

    return image;
}

- (UIImage *)activityViewController:(UIActivityViewController *)activityViewController thumbnailImageForActivityType:(NSString *)activityType suggestedSize:(CGSize)size
{
    //The filtered image is the image to display on the other side.
    return [[UIImage alloc] init];
}

@end

If you execute the sample like this (Use menu item "Send Image After Preprocessing", press "SHARE" Button) it will often or mostly fail to deliver all 9 images to the camera roll.

IF you uncomment the 4 lines in "APLAsyncImageActivityItemProvider.m" that basically just scale the output image THEN it will work ALWAYS.

Can you tell me why ? I feel that if i know the answer to that riddle i can also fix my app.

Thank you,

Nils


回答1:


The reason for this issue is pretty simple.

There are limited number of writer threads available to use by the app, so writing too many images simulteneously may fail due to "Write Busy" error. You can verify that by trying to manually write these images using UIImageWriteToSavedPhotosAlbum (or corresponding Asset/Photos framework counterparts). So, resizing images just hides the real problem because writing a smaller image takes less time.

The problem can be solved by liming the number of writers and/or retrying in case of error. Also note that -[UIActivityItemProvider item] is a blocking call, but there are no synchronous ways to write to the gallery out of the box. This can be handled with dispatch_semaphore_wait , NSCondition, etc. Or, in case you're using ReactiveCocoa, by simply calling waitUntilCompleted.




回答2:


I would go to say that the [UIImage imageWithImage:image scaledToFitToSize:imageSize] image created is GC before saved to camera roll, but I don't know what is going on in that method without the code. That method is not a normal UIImage method, a category maybe?

EDIT

Replace your for loop code adding to your item array with this code, and then uncomment your resize lines, and see if that works.

NSMutableArray *itemArray = [[NSMutableArray alloc] init];
for( int i = 0; i < 9;i++)
{
    UIImage *aiImage = [[[APLAsyncImageActivityItemProvider alloc] init] image];
    [itemArray addObject:aiImage];
}


来源:https://stackoverflow.com/questions/25874568/ios-uiactivityviewcontroller-using-uiactivityitemprovider-forgets-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!