gpt4 book ai didi

swift - 如何在 Swift 中创建自定义完成 block

转载 作者:行者123 更新时间:2023-11-30 13:34:05 24 4
gpt4 key购买 nike

我正在尝试进行一些后期处理

a.一旦我的一个异步函数完成

b.一旦我所有的异步函数完成。

不幸的是,我在下面的代码中遇到了竞争条件。

func foo(stuff: AnArrayOfObjects, completed: (NSError?)->()) {
// STEP 1 OF CREATING AN OVERALL COMPLETION BLOCK: Create a dispatch group.
let loadServiceGroup: dispatch_group_t = dispatch_group_create()

// Define errors to be processed when everything is complete.
// One error per service; in this example we'll have two
let configError: NSError? = nil
let preferenceError: NSError? = nil

// some more preprocessing / variable declarations here. E.g.:
var counter = 0

// STEP 2 OF CREATING AN OVERALL COMPLETION BLOCK: Adding tasks to a dispatch group
dispatch_group_enter(loadServiceGroup)

// here i may start MULTPILE functions that are asynchronous. For example:
for i in stuff {
estore.fetchRemindersMatchingPredicate(remindersPredicate) {
// MARK: Begininning of thread

// does something here. E.g., count the elements:
counter += 1

// update the UI
dispatch_async(dispatch_get_main_queue()) {
self.sendChangedNotification() // reloads the tableview.
// WARNING: I CAN'T JUST SHOW THE counter RESULTS HERE BECAUSE IT MIGHT NOT BE DONE YET. IT IS ASYNCHRONOUS, IT MIGHT STILL BE RUNNING.
}
}

// STEP 3 OF CREATING AN OVERALL COMPLETION BLOCK: Leave dispatch group. This must be done at the end of the completion block.
dispatch_group_leave(loadServiceGroup)

// MARK: End of thread
}

// STEP 4 OF CREATING AN OVERALL COMPLETION BLOCK: Acting when the group is finished
dispatch_group_notify(loadServiceGroup, dispatch_get_main_queue(), {
// do something when asychrounous call block (above) has finished running. E.g.:
print("number of elements: \(counter)")

// Assess any errors
var overallError: NSError? = nil;

if configError != nil || preferenceError != nil {
// Either make a new error or assign one of them to the overall error.
overallError = configError ?? preferenceError
}

// Call the completed function passed to foo. This will contain additional stuff that I want executed in the end.
completed(overallError)
})
}

最佳答案

说实话,我不太明白你在做什么。但是,我总是使用计数器变量来确定所有异步函数是否完成。

func foo(completionHandler: (success: Bool) -> Void) {
var numberOfTasks = 0
for data in datasource {
// do something preparing
numberOfTasks += 1
}

var numberOfDones = 0
objc_sync_enter(numberOfDones)
data.foo(completionHandler:(){
// do something handling outcome
numberOfDones += 1
if numberOfDones == numberOfTasks {
completionHandler(true)
}
})
objc_sync_exit(numberOfDones)
}

其机制是我们知道要完成的任务总数,并且对于每个任务我们都可以捕获完成事件,因此我们添加了 numberOfDones。因此,每当 numberOfDones == numberOfTasks 时,我们就知道这是最后一个,并且已经完成了。

根据您的代码,我尝试将这个想法应用到它上面。

func foo(stuff: AnArrayOfObjects, completed: ([NSError]?)->()) {
// STEP 1 OF CREATING AN OVERALL COMPLETION BLOCK: Create a dispatch group.
let loadServiceGroup: dispatch_group_t = dispatch_group_create()

// Define errors to be processed when everything is complete.
// One error per service; in this example we'll have two
let configError: NSError? = nil
let preferenceError: NSError? = nil

// some more preprocessing / variable declarations here. E.g.:
var counter = 0

// STEP 2 OF CREATING AN OVERALL COMPLETION BLOCK: Adding tasks to a dispatch group
dispatch_group_enter(loadServiceGroup)

// here i may start MULTPILE functions that are asynchronous. For example:
for i in stuff {
estore.fetchRemindersMatchingPredicate(remindersPredicate) {
// MARK: Begininning of thread

// does something here. E.g., count the elements:
counter += 1

// update the UI
dispatch_async(dispatch_get_main_queue()) {
self.sendChangedNotification() // reloads the tableview.
// WARNING: I CAN'T JUST SHOW THE counter RESULTS HERE BECAUSE IT MIGHT NOT BE DONE YET. IT IS ASYNCHRONOUS, IT MIGHT STILL BE RUNNING.
}
}

// STEP 3 OF CREATING AN OVERALL COMPLETION BLOCK: Leave dispatch group. This must be done at the end of the completion block.
dispatch_group_leave(loadServiceGroup)

// MARK: End of thread
}

var numberOfDones = 0
var errors = [NSError]()

// STEP 4 OF CREATING AN OVERALL COMPLETION BLOCK: Acting when the group is finished
objc_sync_enter(numberOfDones)
dispatch_group_notify(loadServiceGroup, dispatch_get_main_queue(), {
// do something when asychrounous call block (above) has finished running. E.g.:
print("number of elements: \(counter)")

// Assess any errors
var overallError: NSError? = nil;

if configError != nil || preferenceError != nil {
// Either make a new error or assign one of them to the overall error.
errors.append(configError ?? preferenceError!)
}

numberOfDones += 1
if numberOfDones == counter {
// Call the completed function passed to foo. This will contain additional stuff that I want executed in the end.
completed(errors)
}
})
objc_sync_exit(numberOfDones)
}

编辑:

感谢@CouchDeveloper 对我的回答发表评论。我提出了另一个解决方案,通过同步计数器变量来确保线程安全。答案已更新,下面是该解决方案的实验

https://gist.github.com/qiuyujx/7173ea663308cc03f07e8a5c09cf4cba

关于swift - 如何在 Swift 中创建自定义完成 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36275314/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com