【发布时间】: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: 在主线程上被调用,这尤其导致我的一件物品出现问题。以下是正在发生的事情的摘要:
- 我需要调用一些异步运行的方法。为了解决这个问题,我尝试使用调度信号量。这样可以防止方法返回,直到我有机会设置返回值。
- 由于在主线程上调用了
activityViewController:itemForActivityType:,因此它在工作时被锁定。 - 我需要将 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