【问题标题】:Objective-C Return Method-Declared Object From Nested BlockObjective-C 从嵌套块返回方法声明的对象
【发布时间】:2013-08-09 16:44:55
【问题描述】:

在以下代码块中,第一个方法调用第二个方法,该方法应返回地理编码过程的结果:

- (void)foo {
    CLPlacemark *currentMark = [self reverseGeocodeLocation:locationManager.location];
}

- (CLPlacemark *)reverseGeocodeLocation:(CLLocation *)location {
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    __block CLPlacemark *placeMark;
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        if (!error) {
            if ([placemarks firstObject])
                placeMark = [placemarks firstObject];
        }
    }];
    return placeMark;
}

但是,由于程序的执行,在继续之前不会等待地理编码完成(因此完成块),总是存在placeMark 变量将在地理编码过程完成之前未经实例化返回的危险,并且调用完成块。在向 Web 服务发出 HTTP 请求时,我遇到了同样的困境,但结果在不确定的时间内不会返回。

到目前为止,我看到的唯一解决方案是将foo 中的所有代码嵌套在地理编码器的完成块中,这很快就会变得非常丑陋且难以维护。

foo 中的currentMark 变量设置为第二个方法的完成块的结果而不将其嵌套在块中的最佳方法是什么?

【问题讨论】:

    标签: ios objective-c oop objective-c-blocks


    【解决方案1】:

    不让函数返回值,只需添加一个回调块来返回值。

    试试这个:

    - (void)reverseGeocodeLocation:(CLLocation *)location withCallback:(void(^)(CLPlacemark *resultPlacemark, NSError *error))_block {
        CLGeocoder *geocoder = [[CLGeocoder alloc] init];
        [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
            _block([placemark objectAtIndex:0], error);
        }];
    }
    

    然后 foo 将是

     - (void)foo {
                __block CLPlacemark *currentMark;
                [self reverseGeocodeLocation:(CLLocation *)location withCallback:(CLPlacemark *mark, NSError *error) {
                   currentMark = mark;
                }];
     }
    

    【讨论】:

    • 是的,不过,这只是扭转了问题。您仍然会得到一个完成块,然后您必须将所有附加代码分层,以确保 foo 中的 currentMark 不为零。
    • 当前标记是从地理编码器中以一个块的形式返回的,因此您实际上别无选择。为什么会有问题?
    • 好吧,如果您遵守您编写的方法(或我目前的方法),那么当您在以前的。它只是不是很优雅。
    • 哈哈。是的。很多丑陋的牙套。异步编程很难。但是我们不知道是谁在调用 foo,所以假设调用者不需要阻塞。现在,您将开始链接控制器和视图,以及与委托无关的内容。
    【解决方案2】:

    似乎总体上处理此问题的最佳方法是使用委托。这样,程序的流程就不会因为等待完成块返回的不确定时间而受到阻碍。

    这是我决定的一个简短示例:

    - (void)reverseGeocodeLocation:(CLLocation *)location {
        CLGeocoder *geocoder = [[CLGeocoder alloc] init];
        [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
            if (!error) {
                if ([placemarks firstObject])
                    [delegate performSelectorOnMainThread:@selector(done:) withObject:[placemarks firstObject];
            }
        }];
        return placeMark;
    }
    

    事后看来,这实际上看起来相当优雅。主线程的控制流(即 UI 呈现)不受任何阻碍,查询数据的视图控制器本质上可以“通知”数据已加载,而不是直接要求返回值。

    【讨论】:

      猜你喜欢
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多