Objective-C 顺序执行两个完成块

Posted

技术标签:

【中文标题】Objective-C 顺序执行两个完成块【英文标题】:Objective-C sequentially Executing Two Completion Blocks 【发布时间】:2018-05-25 18:28:59 【问题描述】:

我目前正致力于使 DJI 产品能够自主执行航点任务,改编自 DJI 教程 (https://developer.dji.com/mobile-sdk/documentation/ios-tutorials/GSDemo.html)。所以我试图将所有流程整合到一个功能中。这是我必须集成的两个完成块:

[[self missionOperator] uploadMissionWithCompletion:^(NSError * _Nullable error) 
    if (error)
        ShowMessage(@"Upload Mission failed", error.description, @"", nil, @"OK");
    else 
        ShowMessage(@"Upload Mission Finished", @"", @"", nil, @"OK");
    
];

和:

[[self missionOperator] startMissionWithCompletion:^(NSError * _Nullable error) 
    if (error)
        ShowMessage(@"Start Mission Failed", error.description, @"", nil, @"OK");
    else
    
        ShowMessage(@"Mission Started", @"", @"", nil, @"OK");
    
];

为了使第二个成功运行,第一个必须首先完全执行。这似乎不是一个难题,但在尝试添加延迟或调度后我无法弄清楚。

感谢任何帮助。谢谢。

【问题讨论】:

现在的行为是什么?该信息可能会有所帮助。为什么不在第一个函数中设置一个布尔值,然后在第二个函数中检查它。 我试图用布尔值确认执行状态。但问题是,随着上传命令的执行,ShowMessage命令会立即执行,但其中的所有进程并没有立即完成。所以随着布尔值的变化,启动命令执行,程序发现因为上传没有完成,所以无法运行。 是的,在这种情况下你会想要使用异步调度队列。 为什么不同步调度,因为我需要按顺序执行?抱歉,我是这个 XD 的新手 串行队列? NSOperations 有依赖关系? 【参考方案1】:

来自the iOS version of the docs you linked,-[DJIWaypointMissionOperator uploadMissionWithCompletion:] 的文档说:

如果启动成功,使用addListenerToUploadEvent:withQueue:andBlock接收详细进度。

所以,你会做这样的事情:

[[self missionOperator] uploadMissionWithCompletion:^(NSError * _Nullable error) 
    if (error)
    
        ShowMessage(@"Upload Mission failed", error.description, @"", nil, @"OK");
    
    else
    
        ShowMessage(@"Upload Mission Started", @"", @"", nil, @"OK");

        [[self missionOperator] addListenerToUploadEvent:self
                                               withQueue:nil
                                                andBlock:^(DJIWaypointMissionUploadEvent *event)
            if (event.currentState == DJIWaypointMissionStateReadyToExecute)
            
                [[self missionOperator] startMissionWithCompletion:^(NSError * _Nullable error) 
                    if (error)
                    
                        ShowMessage(@"Start Mission Failed", error.description, @"", nil, @"OK");
                    
                    else
                    
                        ShowMessage(@"Mission Started", @"", @"", nil, @"OK");
                    
                ];
            
            else if (event.error)
            
                ShowMessage(@"Upload Mission failed", event.error.description, @"", nil, @"OK");
            
        ];
    
];

【讨论】:

如果这是两个通用的完成块,您将是正确的。但是在后台,有一个变量跟踪进程的状态。我可以访问它的值,但不知道如何更改。因此,uploadMissionWithCompletion 将该变量从“准备上传”更改为“正在上传”。当上传实际完成时,状态变为“已上传”。只有当状态变为“已上传”时,“startMissionWithCompletion”才会执行。 这是一个与此相关的页面 (developer.dji.com/api-reference/android-api/Components/Missions/…)。 那么当上传没有真正完成时,你提供给upload...方法的完成处理程序会被调用? 是的。所以我认为我应该在某处添加延迟。但我需要确保 startMission 正在等待,uploadMission 应该继续运行直到它完全完成。 如果“上传任务完成”还没有真正完成,为什么还要记录呢?在事情完成之前调用完成处理程序是一个非常奇怪的设计。无论如何,我已经编辑了我的答案以显示替代方案。【参考方案2】:

您的代码看起来正确。我遇到了同样的问题,在我的任务完成上传后,我的missionOperator 的currentState 将恢复为DJIWaypointMissionStateReadyToUpload 而不是DJIWaypointMissionStateReadyToExecute。该任务已通过有效性检查,但实际上由于个别航点的曲线要求无效(cornerRadiusInMeters 属性)而无效。

来自文档:

/**
 *  Corner radius of the waypoint. When the flight path mode  is
 *  `DJIWaypointMissionFlightPathCurved` the flight path near a waypoint will be  a
 *  curve (rounded corner) with radius [0.2,1000]. When there is a corner radius,
 *  the aircraft will never  go through the waypoint. By default, the radius is 0.2
 *  m. If the corner is made of three adjacent waypoints (Short for A,B,C)  . Then
 *  the radius of A(short for Ra) plus radius of B(short for Rb) must be smaller
 *  than the distance between  A and B. The radius of the first and the last
 *  waypoint in a mission does not affect the flight path and it should keep the
 *  default value (0.2m).
 */

希望这对某人有所帮助。

【讨论】:

以上是关于Objective-C 顺序执行两个完成块的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Objective-C 的完成块转换为 Swift?

IOS/Objective-C:从完成块中检索 NSArray

在swift文件中调用objective-C属性块,完成块属性变为零

IOS/Objective-C:调用完成块的语法

如何在objective-c ios中等待完成块完成[重复]

用于 for 循环内动画的 Objective-C 完成块(暂停循环处理)