【问题标题】:How can I vary the items used by UIActivityViewController in this scenario?在这种情况下,如何改变 UIActivityViewController 使用的项目?
【发布时间】:2016-09-20 11:15:46
【问题描述】:

我有一个带有分享按钮的应用。我想根据活动类型自定义共享的内容。例如,消息可能会获取图像和文本,而 AirDrop 只会获取文件。

我实际上已经完美地工作了,我使用的代码在 iOS 10 到每个版本的 iOS 中都运行良好。但我意识到我在不应该返回的地方返回 nil,所以我'我正在想办法解决这个问题。

我这样做是为了设置我的活动视图控制器:

JUNActivityProvider *fileProvider = [[JUNActivityProvider alloc] initWithPlaceholderItem:[NSObject new]];
fileProvider.objectID = objectID;
fileProvider.fileURL = fileURL;

JUNActivityProvider *textProvider = [[JUNActivityProvider alloc] initWithPlaceholderItem:[NSString new]];
textProvider.objectID = objectID;

...

UIActivityViewController *activityController = [[UIActivityViewController alloc]
    initWithActivityItems:@[fileProvider,imageProvider,textProvider,urlProvider,printFormatter]
    applicationActivities:nil];

然后在JUNActivityProvider中,我有一个item方法,根据activityType自定义返回值:

- (id)item {

    if (self.fileURL) {

        if ([self.activityType isEqualToString:UIActivityTypeAirDrop]) {

            // Create the file
            return url;

        }

    } else if ([self.placeholderItem isKindOfClass:[UIImage class]]) {

        if ([self.activityType isEqualToString:UIActivityTypeAirDrop] == NO &&
            [self.activityType isEqualToString:UIActivityTypeMail] == NO &&
            [self.activityType isEqualToString:UIActivityTypePrint] == NO) {

            // Create the image
            return image;

        }

    } else if ([self.placeholderItem isKindOfClass:[NSString class]]) {

        if ([self.activityType isEqualToString:UIActivityTypeMail]) {

            return @"example one";

        } else if ([self.activityType isEqualToString:UIActivityTypeMessage] ||
            [self.activityType isEqualToString:UIActivityTypeCopyToPasteboard]) {

            return @"example two";

        }

    }

    return nil;

}

最后返回 return nil 是问题所在。它工作正常,并且完全符合我的要求——当它为 nil 时,该项目未共享。书面文档没有说它必须返回一个值,但是头文件确实:

- (nonnull id)item; // 当用户选择一个活动时在辅助线程上调用。你必须继承并返回一个非零值。

我不想在预期非空值时返回 nil 来冒险崩溃,所以我需要解决这个问题。据我所知,我唯一的选择是停止使用UIActivityItemProvider,而是自己实现UIActivityItemSource 协议。该协议包括方法activityViewController:itemForActivityType:,它明确指出您可以在那里返回nil:

如果为单个活动类型注册了多个项目,则可能为 nil,只要其中一个项目返回实际值。

完美。但问题是:activityViewController:itemForActivityType: 在主线程上被调用,这尤其导致我的一件物品出现问题。以下是正在发生的事情的摘要:

  1. 我需要调用一些异步运行的方法。为了解决这个问题,我尝试使用调度信号量。这样可以防止方法返回,直到我有机会设置返回值。
  2. 由于在主线程上调用了activityViewController:itemForActivityType:,因此它在工作时被锁定。
  3. 我需要将 UIView 绘制到图像中。如果我尝试在主线程上完成这项工作,那么在信号量超时之前什么都不会发生。但如果我不在主线程上执行此操作,它就会崩溃。

我不知道如何处理这个问题。基本上我需要在我准备好之前阻止方法返回,但是我不能锁定主线程,因为我需要在那里做一些工作。这似乎……不可能?有什么办法可以做到吗?

【问题讨论】:

  • 您是否尝试过从之前的尝试(UIActivityItemProvider)中返回[NSNull null]?这是一个“非零”返回值,因为它是一个对象,但通常在 Cocoa API 中用于表示空/空结果(我在其他地方使用 UIActivityItemSource 也成功了。
  • @tgaul: 使用[NSNull null] "works" 因为它满足nonnull 的要求并且似乎不会引起任何问题,但这让我非常紧张——我无法知道它对那个物体做了什么。我更倾向于坚持使用nil,因为这多年来没有引起任何明显的问题。
  • 我提交了一个错误报告,建议将 item 属性设为可为空:openradar.me/radar?id=4563896690016256 或 rdar://28394697
  • 我很想看到JUNActivityProvider 。有没有开源那段代码的计划? :D
  • @user4992124:它只是UIActivityItemProvider 的子类。其中大部分都是针对我的应用程序的——所有对其他人有用的内容都包含在我的问答中。

标签: ios objective-c multithreading uikit uiactivityviewcontroller


【解决方案1】:

提交enhancement request 后,我正要放弃并决定返回nil[NSNull null]。但后来我意识到这个问题绝对有解决方案。

虽然 UIActivityItemProvider 包含了一堆自己的功能,但它仍然在很大程度上实现了 UIActivityItemSource 协议。我知道。我没有考虑的是,这意味着我可以覆盖activityViewController:itemForActivityType: 并在适当的时候返回nil 那里

所以我的item 方法的最后一行现在看起来像这样:

return self.placeholderItem;

你也可以在这里返回[NSNull null],或者任何对象。我选择 placeholderItem 是因为它看起来更安全一些——至少我知道它会返回一个预期类型的​​对象,以防实现发生任何变化。

然后我要做的就是添加我自己的activityViewController:itemForActivityType: 实现(我们允许返回nil):

- (nullable id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType {
    id item = [super activityViewController:activityViewController itemForActivityType:activityType];
    if ([item isEqual:self.placeholderItem]) return nil;
    return item;
}

只需调用 super 来获取项目,如果它是您不想包含的内容,则返回 nil,如果是,则返回该项目。请注意,如果您的 placeholderItem 可能与您实际确实想要分享的内容相同,则您需要稍微更改此实现,但相同的基本概念应该可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 2015-11-30
    • 2017-05-16
    • 2012-10-06
    • 2011-05-18
    • 2019-11-29
    • 2022-01-23
    • 2018-05-20
    相关资源
    最近更新 更多