在这种情况下,如何更改UIActivityViewController使用的项目?

机器人垫片

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

我实际上可以完美地工作,并且我使用的代码在iOS 10和iOS 10的每个版本中都能正常工作。但是我意识到我在不应该返回的位置返回了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最后的回报就是问题所在。它可以正常工作,并且完全符合我的要求,当没有共享该项目时,它几乎为零。书面文档没有说必须返回一个值,但是头文件可以:

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

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

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

完美的。但这是问题所在:activityViewController:itemForActivityType:在主线程上被调用,这尤其导致我的其中一个项目出现了问题。这是正在发生的事情的摘要:

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

我不知道如何处理这个问题。基本上,我需要防止方法返回直到准备好为止,但是由于需要在那里做一些工作,所以无法锁定主线程。看来...不可能吗?有什么办法可以使这项工作吗?

机器人垫片

提出增强请求后,我即将放弃并选择归还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要永远等于你真正的东西想分享,您需要更改这个实现的位,但相同的基本概念应该工作。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章