iOS UIActivityViewController 使用 UIActivityItemProvider “忘记”项目

Posted

技术标签:

【中文标题】iOS UIActivityViewController 使用 UIActivityItemProvider “忘记”项目【英文标题】:iOS UIActivityViewController using UIActivityItemProvider "forgets" items 【发布时间】:2014-09-16 17:03:04 【问题描述】:

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

我受到 Apple Airdrop 示例的“启发”: AirdropSample download

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

我无法在此处发布我的应用程序,但我修改了上述示例,使其在将所有图像传送到相机胶卷时也会随机“失败”...

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

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

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

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

你能告诉我为什么吗?我觉得如果我知道这个谜语的答案,我也可以修复我的应用程序。

谢谢,

尼尔斯

【问题讨论】:

我遇到了同样的问题。你有没有找到解决这个问题的方法? 【参考方案1】:

这个问题的原因很简单。

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

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

【讨论】:

【参考方案2】:

我会说创建的[UIImage imageWithImage:image scaledToFitToSize:imageSize] 图像在保存到相机胶卷之前是 GC,但我不知道没有代码在该方法中发生了什么。那个方法不是普通的 UIImage 方法,可能是一个类别?

编辑

用此代码替换添加到项目数组的 for 循环代码,然后取消注释调整大小的行,看看是否可行。

NSMutableArray *itemArray = [[NSMutableArray alloc] init];
for( int i = 0; i < 9;i++)

    UIImage *aiImage = [[[APLAsyncImageActivityItemProvider alloc] init] image];
    [itemArray addObject:aiImage];

【讨论】:

它是示例中能够调整图像大小的方法。 (UIImage+Resize.h/m)。 这无助于确定在保存之前是否正在对某些内容进行垃圾收集。 我怀疑是这样的,我将下载链接发布到上面的示例中,您知道如何防止图像被“丢弃”吗?正如您可能猜到的那样,我是一个 OBJ-C 菜鸟,我的应用程序 99% 是 C++,我只需要 OBJ_C 来实现“共享”功能...... 不确定 UIActivityViewController 是如何知道调用 item 来获取图像的。尝试将图像添加到数组而不是 APLAsyncImageActivityItemProvider 对象...[[APLAsyncImageActivityItemProvider alloc] init].image 应该可以工作。 对不起,应该是[[[APLAsyncImageActivityItemProvider alloc] init] image]

以上是关于iOS UIActivityViewController 使用 UIActivityItemProvider “忘记”项目的主要内容,如果未能解决你的问题,请参考以下文章

IO复用阻塞IO非阻塞IO同步IO异步IO

四种IO模型‘阻塞IO/非阻塞IO/信号驱动IO/异步IO‘

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别