在这种情况下,我如何改变 UIActivityViewController 使用的项目?
How can I vary the items used by UIActivityViewController in this scenario?
我有一个带有分享按钮的应用程序。我想根据 activity 类型自定义共享的内容。例如,消息可能会获取图像和文本,而 AirDrop 只会获取文件。
我实际上已经完美地工作了,我使用的代码在 iOS 到 iOS 10 的每个版本中都运行良好。但我意识到我是 return在我不应该的地方使用 nil,所以我想弄清楚如何解决这个问题。
我做这样的事情来设置我的 activity 视图控制器:
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
:
自定义 return 值
- (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;
}
最后那个returnreturn nil
就是问题所在。它工作正常并且完全符合我的要求——当它为 nil 时,该项目不被共享。书面文档没有说它必须 return 一个值,但头文件确实如此:
- (nonnull id)item;
// called on secondary thread when user selects an activity. you must subclass and return a non-nil value.
我不想在需要非空值时 returning nil 冒崩溃的风险,所以我需要解决这个问题。据我所知,我唯一的选择是停止使用 UIActivityItemProvider
,而是自己实现 UIActivityItemSource
协议。该协议包括方法 activityViewController:itemForActivityType:
,它清楚地表明你 can return nil there:
May be nil if multiple items were registered for a single activity type, so long as one of the items returns an actual value.
完美。但问题是:activityViewController:itemForActivityType:
在主线程上被调用,这导致我的一个项目出现问题。以下是正在发生的事情的摘要:
- 我需要异步调用一些 运行 的方法。为了解决这个问题,我尝试使用调度信号量。这使得方法从 returning 直到我有机会设置 return 值。
- 由于在主线程上调用了
activityViewController:itemForActivityType:
,因此它在工作时会被锁定。
- 我需要将 UIView 绘制到图像中。如果我尝试在主线程上执行该工作,则在信号量超时之前什么也不会发生。但是如果我不在主线程上执行它,它就会崩溃。
我不知道如何处理这个问题。基本上我需要在我准备好之前保持方法从 returning 开始,但是我不能锁定主线程,因为我需要在那里做一些工作。这好像……不可能?有什么办法可以做到这一点吗?
提交 enhancement request 后,我正准备放弃并选择 returning nil
或 [NSNull null]
。但后来我意识到这个问题绝对有解决办法。
虽然 UIActivityItemProvider 包含了一系列自己的功能,但它仍然在很大程度上实现了 UIActivityItemSource 协议。我知道。我没有考虑的是,这意味着我可以在适当的时候覆盖 activityViewController:itemForActivityType:
和 return nil
there。
所以我的 item
方法的最后一行现在看起来像这样:
return self.placeholderItem;
您也可以在此处 return [NSNull null]
或任何对象。我选择了 placeholderItem 是因为它看起来更安全一些 — 至少我知道它是 returning 一个预期类型的对象,以防实现发生任何变化。
然后我所要做的就是添加我自己的 activityViewController:itemForActivityType:
实现(我们 是 允许 return 零):
- (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 即可获取该项目,return nil 如果您不想包含该项目,或者 return 如果是该项目。请注意,如果您的 placeholderItem
可能永远等于您实际上 做 想要分享的东西,您将需要稍微更改此实现 — 但相同的基本概念应该有效。
我有一个带有分享按钮的应用程序。我想根据 activity 类型自定义共享的内容。例如,消息可能会获取图像和文本,而 AirDrop 只会获取文件。
我实际上已经完美地工作了,我使用的代码在 iOS 到 iOS 10 的每个版本中都运行良好。但我意识到我是 return在我不应该的地方使用 nil,所以我想弄清楚如何解决这个问题。
我做这样的事情来设置我的 activity 视图控制器:
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;
}
最后那个returnreturn nil
就是问题所在。它工作正常并且完全符合我的要求——当它为 nil 时,该项目不被共享。书面文档没有说它必须 return 一个值,但头文件确实如此:
- (nonnull id)item;
// called on secondary thread when user selects an activity. you must subclass and return a non-nil value.
我不想在需要非空值时 returning nil 冒崩溃的风险,所以我需要解决这个问题。据我所知,我唯一的选择是停止使用 UIActivityItemProvider
,而是自己实现 UIActivityItemSource
协议。该协议包括方法 activityViewController:itemForActivityType:
,它清楚地表明你 can return nil there:
May be nil if multiple items were registered for a single activity type, so long as one of the items returns an actual value.
完美。但问题是:activityViewController:itemForActivityType:
在主线程上被调用,这导致我的一个项目出现问题。以下是正在发生的事情的摘要:
- 我需要异步调用一些 运行 的方法。为了解决这个问题,我尝试使用调度信号量。这使得方法从 returning 直到我有机会设置 return 值。
- 由于在主线程上调用了
activityViewController:itemForActivityType:
,因此它在工作时会被锁定。 - 我需要将 UIView 绘制到图像中。如果我尝试在主线程上执行该工作,则在信号量超时之前什么也不会发生。但是如果我不在主线程上执行它,它就会崩溃。
我不知道如何处理这个问题。基本上我需要在我准备好之前保持方法从 returning 开始,但是我不能锁定主线程,因为我需要在那里做一些工作。这好像……不可能?有什么办法可以做到这一点吗?
提交 enhancement request 后,我正准备放弃并选择 returning nil
或 [NSNull null]
。但后来我意识到这个问题绝对有解决办法。
虽然 UIActivityItemProvider 包含了一系列自己的功能,但它仍然在很大程度上实现了 UIActivityItemSource 协议。我知道。我没有考虑的是,这意味着我可以在适当的时候覆盖 activityViewController:itemForActivityType:
和 return nil
there。
所以我的 item
方法的最后一行现在看起来像这样:
return self.placeholderItem;
您也可以在此处 return [NSNull null]
或任何对象。我选择了 placeholderItem 是因为它看起来更安全一些 — 至少我知道它是 returning 一个预期类型的对象,以防实现发生任何变化。
然后我所要做的就是添加我自己的 activityViewController:itemForActivityType:
实现(我们 是 允许 return 零):
- (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 即可获取该项目,return nil 如果您不想包含该项目,或者 return 如果是该项目。请注意,如果您的 placeholderItem
可能永远等于您实际上 做 想要分享的东西,您将需要稍微更改此实现 — 但相同的基本概念应该有效。