problems using Grand Central Dispatch IOS Swift Xcode 6.3.1 -
i'm learning swift , having hard time understanding multithreading issues..
specific problem im having i'm loading data internet , trying return array ("broadcasts") containing data while using dispatch_async .
my problem return execution empty array happens before array filled data (this line "println(broadcasts)" happens array returns empty.. )
here code:
import uikit public class broadcastrequest { func requestnewbroadcasts() -> [broadcastmodel] { var broadcasts = [broadcastmodel]() var sectionsofbroadcasts = [[broadcastmodel]]() datamanager.getbroadcastsfrom׳tweeterwithsuccess { (youtubedata) -> void in dispatch_async(dispatch_get_main_queue()) { () -> void in let json = json(data: youtubedata) if let broadcastsarray = json["result"].array { broadcastdict in broadcastsarray{ var broadcastid: string? = broadcastdict["id"].string var broadcasturl: string? = broadcastdict["broadcast"].string datamanager.getbroadcastdetailsfromyoutubewithsuccess(broadcasturl!) { (youtubedata) -> void in dispatch_async(dispatch_get_main_queue()) { () -> void in let json2 = json(data: youtubedata) if let broadcastdetailsdict = json2["result"].dictionary { var cover: string! = broadcastdetailsdict["cover"]!.string var caption: string! = broadcastdetailsdict["caption"]!.string var broadcast = broadcastmodel(id: broadcastid, broadcasturl: broadcasturl, cover: cover, caption: caption) broadcasts.append(broadcast) **println(broadcasts)** } } } } } } } **return broadcasts** } }
after looking @ answers have changed code this:
import uikit public class broadcastrequest { func requestnewbroadcasts() { var broadcasts = [broadcastmodel]() var sectionsofbroadcasts = [[broadcastmodel]]() datamanager.getbroadcastsfrom׳tweeterwithsuccess { (youtubedata) -> void in dispatch_async(dispatch_get_main_queue()) { () -> void in let json = json(data: youtubedata) if let broadcastsarray = json["result"].array { broadcastdict in broadcastsarray{ var broadcastid: string? = broadcastdict["id"].string var broadcasturl: string? = broadcastdict["broadcast"].string datamanager.getbroadcastdetailsfromyoutubewithsuccess(broadcasturl!) { (youtubedata) -> void in dispatch_async(dispatch_get_main_queue()) { () -> void in let json2 = json(data: youtubedata) if let broadcastdetailsdict = json2["result"].dictionary { var cover: string! = broadcastdetailsdict["cover"]!.string var caption: string! = broadcastdetailsdict["caption"]!.string var broadcast = broadcastmodel(id: broadcastid, broadcasturl: broadcasturl, cover: cover, caption: caption) broadcasts.append(broadcast) println(broadcasts) } } } } } } } **tableviewcontroller.requestfinished(broadcasts)** } }
and in class tableviewcontroller-
public class tableviewcontroller: uitableviewcontroller { ... ... public func requestfinished(requestedbroadcasts: [broadcastmodel]) { self.broadcasts = requestedbroadcasts self.tableview.reloaddata() }
now error: cannot invoke 'requestfinished' argument list of type '([(broadcastmodel)])'
your code wrong. call gcd function dispatch_async returns immediately, before code in closure has begun executing. that's nature of concurrent programming.
you can't write async code makes call , has answer on next line. instead need change logic make call dispatch async , return , forget request until block completes. put code handles result inside closure. can add call inside closure calls out app on main thread notify processing complete.
edit:
your new code has multiple problems:
your call dispatch_async using main queue, queue on main thread. if goal code run in background, code fails that.
the call tableviewcontroller.requestfinished(broadcasts)
still in wrong place. needs inside block, after data has been fetched. needs performed on main thread.
the call tableviewcontroller.requestfinished(broadcasts)
appears sending message tableviewcontroller class rather instance of tableviewcontroller class, wrong. can't fix unless block has access instance of tableviewcontroller want send message to.
you should refactor requestnewbroadcasts method follows:
- make not return anything. (the result won't available until after async block completes anyway.)
- make requestnewbroadcasts take completion block (or rather closure, called in swift). rid of
tableviewcontroller.requestfinished(broadcasts)
call entirely, , instead have network code call completion block once network request complete. - make call dispatch_async use background queue rather main queue task runs in background.
- make requestnewbroadcasts method invoke completion block on main thread.
each of steps going require work , research on part.
figuring out how add closure parameter take digging. (see swift programming language ibook. explains well.)
figuring out how background queue take work. (see xcode docs documentation on gcd. in particular @ dispatch_get_global_queue)
figuring out how make call main thread background thread take research (again see xcode docs on gcd. hint: current call dispatch_async sending block queue on main thread.).
Comments
Post a Comment