【问题标题】:How to cancel UIActivityItemProvider and don't show activity?如何取消 UIActivityItemProvider 并且不显示活动?
【发布时间】:2014-02-26 09:59:02
【问题描述】:

我正在使用UIActivityItemProvider 子类来提供自定义数据。但有时获取数据会失败,我不想展示活动(例如消息编写器)。在item 方法中尝试了[self cancel]return nil;,但消息编写器仍然显示(带有空消息)。

【问题讨论】:

  • 我想知道是否有人也为此找到了解决方法。这绝对是一个 iOS SDK 错误。我建议为此安装一个雷达。
  • 我也有同样的问题。仍在寻找解决方法。
  • 还在寻找解决方案。

标签: nsoperation uiactivityviewcontroller uiactivity


【解决方案1】:

如果您在从 -(id)item 返回之前关闭 UIActivityViewController,它将不会显示用户选择的活动。

为此,您首先需要在activityViewControllerPlaceholderItem 中获取activityViewController。在 -(id)item 在 dispatch_async 中运行代码以更新进度并在完成/错误时关闭,我正在使用 Promise 库。

在您的 UIActivityItemProvider 子类中执行类似于以下示例的操作。

-(id) activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{ self.avc = activityViewController;
  return NSURL;
}

-(id)item
{ __block BOOL fileProcDone = NO;
  dispatch_async(dispatch_get_main_queue(), ^
  { self.pvc = [[ProgressAlertVC alloc] init];
    [self.vc presentViewController:self.pvc animated:YES completion:nil];
    [[[[self promiseMakeFile]
    progressed:^(float progress)
    { self.pvc.progress = progress;
    }]
    fulfilled:^(id result)
    { [self.pvc dismissViewControllerAnimated:YES completion:^
      { fileProcDone = YES;
      }];
    }]
    failed:^(NSError *error)
    { [self.pvc dismissViewControllerAnimated:YES completion:^
      { [self.vc dismissViewControllerAnimated:YES completion:^
        { fileProcDone = YES;
        }];
      }];
    }];
  });
  while (!fileProcDone)
  { [NSThread sleepForTimeInterval:0.1];
  }; 
  return NSURL;
}

这将导致来自活动扩展的控制台日志消息,但只要它们正确处理错误,一切都应该没问题。如果您从 -(id)activityViewController: itemForActivityType: 返回 nil,您不会收到控制台错误,但即使您此时关闭 UIActivityViewController,也会获得用户选择的活动。

【讨论】:

    【解决方案2】:

    您只需要调用 UIActivityItemProvider 的cancel 方法即可。由于 UIActivityItemProvider 是一个 NSOperation,调用cancel 将标记操作取消。

    此时,您有几个选项可以实际停止长时间运行的任务,具体取决于您的任务结构。您可以覆盖cancel 方法并在那里取消,只要确保也调用[super cancel]。第二个选项是在item 方法中检查isCancelled 的值。

    项目提供者示例

    import UIKit
    import Dispatch
    
    class ItemProvider: UIActivityItemProvider {
    
        override public var item: Any {
            let semaphore = DispatchSemaphore(value: 0)
    
            let message = "This will stop the entire share flow until you press OK. It represents a long running task."
            let alert = UIAlertController.init(title: "Hello", message: message, preferredStyle: .alert)
            let action = UIAlertAction.init(title: "OK", style: .default, handler:
                { action in
                    semaphore.signal()
            })
            let cancel = UIAlertAction.init(title: "CANCEL", style: .destructive, handler:
                { [weak self] action in
                    self?.cancel()
                    semaphore.signal()
            })
    
            alert.addAction(action)
            alert.addAction(cancel)
    
            //Truly, some hacking to for the purpose of demonstrating the solution
            DispatchQueue.main.async {
                UIApplication.shared.delegate?.window??.rootViewController?.presentedViewController!.present(alert, animated: true, completion: nil)
            }
    
            // We can block here, because our long running task is in another queue
            semaphore.wait()
    
            // Once the item is properly cancelled, it doesn't really matter what you return
            return NSURL.init(string: "blah") as Any
        }
    }
    

    在视图控制器中,像这样启动一个共享活动。

        let provider = ItemProvider.init(placeholderItem: "SomeString")
        let vc = UIActivityViewController.init(activityItems: [provider], applicationActivities: nil)
    
        self.present(vc, animated: true, completion: nil)
    

    【讨论】:

    • 我实现了这个例子,但是它在 iOS14 上不起作用。当我点击任何共享意图的应用时,什么都没有发生
    猜你喜欢
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多