【问题标题】:Returning method object from inside block从块内部返回方法对象
【发布时间】:2014-04-11 15:35:19
【问题描述】:

我想知道如何正确执行以下操作:我有一个方法是返回一个 NSData 对象。它从UIDocument 获取NSData 对象。 NSData 对象可能会变大,所以我想确保它在响应开始之前完全加载。因此,我想从块本身返回方法的值。所以是这样的:

- (NSData*)getMyData {
  MyUIDocument *doc = [[MyUIDocument alloc] initWithFileURL:fileURL];
  [doc openWithCompletionHandler:^(BOOL success) {

    if (success) {
      return doc.myResponseData; // this is to be the return for the method not the block
    }
  }];
}

这会导致错误,因为return 显然是指blockreturn

我怎样才能做到这一点而不必使线程阻塞等待/while循环?

谢谢。

【问题讨论】:

    标签: ios objective-c block uidocument completionhandler


    【解决方案1】:

    你不能。接受这样一个事实,即您尝试做的是异步的,并向您的 getMyData 方法添加一个完成块参数,该方法在调用内部完成处理程序时被调用。 (并从方法签名中删除return):

    - (void)getMyDataWithCompletion:(void(^)(NSData *data))completion {
        MyUIDocument *doc = [[MyUIDocument alloc] initWithFileURL:fileURL];
        [doc openWithCompletionHandler:^(BOOL success) {
            completion((success ? doc.myResponseData : nil));
        }];
    }
    

    swift中也存在同样的问题,可以添加类似的补全块:

    func getMyData(completion: ((data: NSData?) -> Void) {
        data = ...
        completion(data)
    }
    

    【讨论】:

    • 我很困惑。那不会又是从块内部返回一个方法值吗?
    • 不,您在任何地方都没有return 声明。您将调用带有回调(传递成功)的方法,并且该回调调用另一个回调(传递数据)。
    • 正如 Wain 在回答中所说,调用是异步的,所以不是调用一个方法并等待它返回并下一个处理结果,而是传递一个处理结果的代码块,并且加载文档后,Wain 的方法会自动调用该块。在现实生活中的例子中,与其说“做这个,完成后告诉我,这样我就可以给这个号码打个电话告诉他这个那个”,而是说“做这个,当你完成后打电话这个号码,然后告诉他这个那个”。
    【解决方案2】:

    open 方法是异步的,这就是为什么您必须提供一个在 open 完成时运行的块。您需要复制它并让您的方法也收到一个代码块,您将在打开完成时执行该代码块。

    您还应该传递您正在包装的调用的成功参数或创建错误,您需要这样做以便调用代码可以采取正确的操作。

    - (void)getMyDataWithCompletion:(void(^)(NSData *data, BOOL success))completion
    {
      MyUIDocument *doc = [[MyUIDocument alloc] initWithFileURL:fileURL];
      [doc openWithCompletionHandler:^(BOOL success) {
        completion(doc.myResponseData, success);
      }];
    }
    

    【讨论】:

      【解决方案3】:

      以下是方法如何用completionHandler声明方法:

      Objective-C

      - (void)getMyDataWithCompletionHandler:(void(^)(NSString *str))completionHandler
      {
          completionHandler(@"Test");
      }
      

      Swift-3

      func showDatePicker(superc: UIViewController, completionHandler:@escaping (String) -> Void)  {
                  completionHandler("Test")
      }
      

      【讨论】:

        猜你喜欢
        • 2018-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多