使用完成处理程序结束循环的方法?

时间:2016-04-13 15:39:53

标签: arrays swift loops completionhandler

也许我有一个理解整体前提的潜在问题,但我试图找出使用一系列项目做某事的最佳方法,并结束 test 一旦找到某个标准,就会提早。

例如,我有一系列名字;
var names = ["Bob", "Billy", "Sarah", "Brandon", "Brian", "Rick"]

我想测试数组中的每个名称,看看它是否存在于数据库中。为此,我使用完成处理程序调用另一个函数;

for name in names {

    TestName(name) { response in

     if response {
         // END THE LOOP
     } else {
         // KEEP GOING
     }
 }

我无法找出 // END THE LOOP 。出于本示例的目的,我只关注第一次响应是否为真(如果Billy存在于数组中,我对测试Sarah,Brandon,Brian或Rick没有兴趣。)

谢谢!

4 个答案:

答案 0 :(得分:3)

在开始循环之前,设置一个标志:

var exitEarly = false
for name in names {

每次通过循环时测试标志:

for name in names {
    if exitEarly {
        break
    }

在TestName响应块中,设置标志:

TestName(name) { response in
    if response {
        exitEarly = true
    } else {
        // KEEP GOING
    }
}

但是,请注意,如果TestName的块是异步执行的,那将无法工作,因为整个循环先于调用任何异步块(这是异步的本质)

答案 1 :(得分:1)

你的情况并不是一个循环的设计。在执行循环内的闭包之前,循环可能完成是可能的。

相反,尝试使用完成块的递归函数:

func databaseHasAName(names: [String], index: Int, completion: (String?) -> ()) {

    guard index < names.count else{
        completion(nil)
        return
    }

    let name = names[index]
    TestName(name) { response in

        if response {
            completion(name)
        } else {
            databaseHasName(names, index: index + 1, completion: completion)
        }
    }
}

这确保了无论响应块的同步性如何,一次只发生一次呼叫

答案 2 :(得分:0)

  1. @noescape属性添加到TestName的闭包参数,以指示闭包不会转义该调用。

  2. 如果要停止,请在TestName调用之外使用变量,设置为false,并在循环内将其设置为true。

  3. 在TestName调用之后,检查变量以查看是否需要中断。

    1. 更改TestName以返回一个值,指示是否应该继续

答案 3 :(得分:0)

我必须和PEEJWEEJ做同样的事情。我的异步任务是Web查询和解析,而且非常密集,for循环总是在这些任务完成之前完成,所以没有办法阻止它们。

所以我将它转换为递归并在我希望它停止时设置一个标志,现在它工作正常。

// ************************************************************************************************************
// MARK: Recursive function
// I changed the loop to be recursive so I could stop when I need to - i.e. when selecting another race
// I set the stopFetching flag in the seque when changing races and the current set of BG queries stops
// ************************************************************************************************************
func getRaceResultsRecursive(race: Race, bibs: [Bib], index: Int, completion: @escaping (Bool?) -> ())
{
    guard index < bibs.count else{
        completion(nil)
        return
    }

    var url: URL
    self.stopFetching = false

    let bibID = bibs[index]
        url = self.athleteResultAPI.formatURL(baseURL: (race.baseURL)!,
                                              rd: (race.rdQueryItem)!,
                                              race: (race.raceQueryItem)!,
                                              bibID: "\(bibID.bib!)",
            detail: (race.detailQueryItem)!,
            fragment: (race.detailQueryItem)!,
            webQueryType: (race.webQueryType!))

    self.athleteResultAPI.fetchAthleteResults(url: url, webQueryType: race.webQueryType!)
    {
        (athleteReturnCode) in
        switch athleteReturnCode
        {
        case let .success(athleteResult):
            self.athleteResults.append(athleteResult)       // Add to collection
            self.delegate?.athleteResultsUpdated()           // update Delegate to notify of change
        case let .failure(error):
            print(error)
            break
        }

        if self.stopFetching {
            completion(true)
        }
        else {
            self.getRaceResultsRecursive(race: race, bibs: bibs, index: index + 1, completion: completion)
        }
    }
}

// ************************************************************************************************************
// getRaceResults
// Get all the bibs to track for this race from the iCloudKit database
// ************************************************************************************************************
func getRaceResults(race: Race)
{
    // get all the races and bibs an put in the Races Store
    raceStore.fetchBibsForRace(race: race, foreignKey: race.recordID)
    {
        (results, error) in
        if let error = error {
            print("Error in fetchBibsForRace(): \(error)")
            return
        }

        // clear the store since we are on a new race
        self.athleteResults.removeAll()
        self.getRaceResultsRecursive(race: race, bibs: race.bibs, index: 0)
        {
            (stopFetching) in
            return
        }

    }
}