iOS UIActivityViewController 使用 UIActivityItemProvider “忘记"项目 [英] iOS UIActivityViewController using UIActivityItemProvider "forgets" items

查看:16
本文介绍了iOS UIActivityViewController 使用 UIActivityItemProvider “忘记"项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个更大的应用程序,应该能够共享多个图像.我使用 UIActivityViewController 和 UIActivityItemProvider 实现了这一点,以异步使用项目(这样我一次只需要准备一个图像,而不必一次用所有图像填充内存来共享它们).

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).

我受到 Apple Airdrop 示例的启发":空投示例下载

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

但是,当使用我的应用进行分享时,例如9 张图像(到相机胶卷 ==保存 9 张图像")只有 4 到 7 张图像最终出现在相机胶卷中,没有任何错误消息.如果我一遍又一遍地重复,有时我会得到 5 张图片或 6 张看似随机的图片.

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...

如果你下载了上面的示例并用这些替换了 4 个文件,就会显示问题:

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

APLAsyncImageViewController.h:

APLAsyncImageViewController.h:

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

@interface APLAsyncImageViewController : UIViewController
@end

APLAsyncImageViewController.m:

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:

APLAsyncImageActivityItemProvider.h:

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

APLAsyncImageActivityItemProvider.m:

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

如果您像这样执行示例(使用菜单项预处理后发送图像",按共享"按钮),它通常或大部分无法将所有 9 个图像传送到相机胶卷.

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.

如果您取消注释APLAsyncImageActivityItemProvider.m"中基本上只是缩放输出图像的 4 行,那么它将始终有效.

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.

谢谢,

尼尔斯

推荐答案

这个问题的原因很简单.

The reason for this issue is pretty simple.

应用程序可用的写入器线程数量有限,因此同时写入过多图像可能会由于写入忙"错误而失败.您可以通过尝试使用 UIImageWriteToSavedPhotosAlbum(或相应的 Asset/Photos 框架对应项)手动编写这些图像来验证这一点.因此,调整图像大小只是隐藏了真正的问题,因为编写较小的图像需要更少的时间.

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.

该问题可以通过限制写入者的数量和/或在出现错误时重试来解决.另请注意, -[UIActivityItemProvider item] 是一个阻塞调用,但没有同步方式可以开箱即用地写入库.这可以通过 dispatch_semaphore_wait 、 NSCondition 等来处理.或者,如果您使用的是 ReactiveCocoa,只需调用 waitUntilCompleted.

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.

这篇关于iOS UIActivityViewController 使用 UIActivityItemProvider “忘记"项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆