Reputation: 43
In my Swift project, I'm trying to process a FIFO queue (I will call it a list here to avoid confusion) in a background thread. When I use dispatch_async, it results in a EXC_BAD_ACCESS error after only some of the list has been executed. I've simplified the code as much as I could into the following playground code. In the playground, when main_thread is set to true, the code processes all 100 items in the list. If it's false, only a handful of items get processed. If the code is in a project, EXC_BAD_ACCESS occurs when main_thread is false. Obviously, I've also tried specifying a serial queue but that doesn't seem to help. What am I missing or not understanding? Thanks.
import UIKit
let main_thread = false
let serial_queue = true
class main_class {
var this_list = list_class()
func run(){
for i in 1...100 {
this_list.add_to_list( String(i) )
}
if main_thread {
this_list.process_list()
} else {
if serial_queue {
let my_serial_queue = dispatch_queue_create("msq", DISPATCH_QUEUE_SERIAL)
dispatch_async(my_serial_queue){()->Void in
self.this_list.process_list()
}
} else {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () ->Void in
self.this_list.process_list()
})
}
}
}
}
class list_class {
var my_list: [String] = []
func add_to_list( this: String ){
my_list.append( this )
}
func process_list(){
if my_list.count > 0 {
print("removing " + my_list[0])
remove_from_list( my_list[0] )
}
}
func remove_from_list( this: String ){
let found = my_list.indexOf( this )
if found != nil {
my_list.removeAtIndex( found! )
process_list()
}
}
}
var blah = main_class()
blah.run()
Upvotes: 4
Views: 2748
Reputation: 43
Thanks to Graham Perks answer that I needed dispatch_group_wait - I ended up with this code working as needed. I hadn't expected to need 2 async calls :( XCPlayground was only required in the playground.
import UIKit
import XCPlayground
var GlobalMainQueue: dispatch_queue_t {
return dispatch_get_main_queue()
}
var GlobalBackgroundQueue: dispatch_queue_t {
return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
}
class main_class {
var this_list = list_class()
var done = "NO"
func run(){
for i in 1...100 {
this_list.add_to_list( String(i) )
}
dispatch_async( GlobalBackgroundQueue ){
let ds_group = dispatch_group_create()
dispatch_group_enter(ds_group)
dispatch_async(GlobalMainQueue){
self.this_list.process_list()
dispatch_group_leave(ds_group)
}
dispatch_group_wait(ds_group, DISPATCH_TIME_FOREVER)
dispatch_async(GlobalMainQueue){
self.done = "YES"
}
}
}
}
class list_class {
var my_list: [String] = []
func add_to_list( this: String ){
my_list.append( this )
}
func process_list(){
if my_list.count > 0 {
print("removing " + my_list[0])
remove_from_list( my_list[0] )
}
}
func remove_from_list( this: String ){
let found = my_list.indexOf( this )
if found != nil {
my_list.removeAtIndex( found! )
process_list()
}
}
}
var blah = main_class()
blah.run()
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
Upvotes: 0
Reputation: 23400
Your main thread is exiting while the background thread is still running. Main thread ends -> process gets terminated.
Set up something for main to block on while the background thread is still operating. For example, use dispatch_group_wait()
; along with dispatch_group_enter()
and dispatch_group_leave()
.
Upvotes: 1