rest - Assigning data from closure after dataTaskWithURL resulting in nil values -
i apologize simplicity of description, i'm new swift language.
i have rest api provides data app. attempting populate table view json feed. essentially, trying best stick mvc patterns use in web development. i've built model of data object, , list model contain individual instances of object.
the actual problem is, when initiate whole process (last code sample) result count 0 that's because data response api call hasn't happened yet. i'd rather not use synchronous calls, i'm feeling that's way i'm going fix this, unless start mucking api calls directly controller itself?
class newsitem { var id: int var headline: string var summary: string var created: string var source: string var company: string var companylogo: uiimage init(headline: string, summary: string, created: string, source: string, company: string, companylogourl: string, id: int) { self.id = id self.headline = headline self.summary = summary self.created = created self.source = source self.company = company if let url = nsurl(string: companylogourl) { if let data = nsdata(contentsofurl: url) { companylogo = uiimage(data: data)! } else { companylogo = uiimage(named: "defaultlogo")! } } else { companylogo = uiimage(named: "defaultlogo")! } } } i have newslist class builds array of news items using closure rest call.
class newslist { var name: string var newsitems: [newsitem] init(named: string, includenewsitems: [newsitem]) { name = named newsitems = includenewsitems } class func getnewsitems() -> [newslist] { return [self.parsednews()] } private class func parsednews() -> newslist { var newsitems = [newsitem]() api.getlatestactivitydata({jsondata, error -> void in if (jsondata != nil) { (_, subjson) in jsondata["data"] { let headline = subjson["headline"].string! let summary = subjson["summary"].string! let created = subjson["created"].string! let source = subjson["source"].string! let company = subjson["company"].string! let companylogo = subjson["companylogo"].string! let id = subjson["id"].int! dispatch_async(dispatch_get_main_queue(), { newsitems.append(newsitem(headline: headline, summary: summary, created: created, source: source, company: company, companylogourl: companylogo, id: id)) }) } } else { print("api data fetch failed") print(error) } }) return newslist(named: "news", includenewsitems: newsitems) } } for call above, i've got following method inside remoteapi class
func getlatestactivitydata(completionhandler: ((json!, nserror!) -> void)!) -> void { let requesturl = self.baseurl + "xxxxxxx" print("request url: " + requesturl) let url = nsurl(string: requesturl)! let request = nsmutableurlrequest(url: url) request.setvalue("text/json; charset=utf-8", forhttpheaderfield: "content-type") let task = nsurlsession.sharedsession().datataskwithurl(url, completionhandler: {data, response, error -> void in if (error != nil) { return completionhandler(nil, error) } print("latest activity response received") let returnstring = nsstring(data: data!, encoding: nsutf8stringencoding) let jsondata = returnstring!.datausingencoding(nsutf8stringencoding)! let readablejson = json(data: jsondata, options: nsjsonreadingoptions.mutablecontainers, error: nil) if (error != nil) { return completionhandler(nil, error) } else { return completionhandler(readablejson, nil) } }) task.resume() } to initiate entire above convoluted process, have in view controller
var newsitems: [newsitem] { var newslist = newslist.getnewsitems() return newslist[0].newsitems } here our pain point. if fire print(newsitems.count) after above call, result 0. second or 2 later, callback handler receive data , begin assigning items newslist array.
how prevent array assignment until data received? going entirely wrong way?
xcode 7 + swift 2.0 + ios 9.0.x
my error in how using closure. depending upon closure assign values outside closure , completion handler return values.
solution:
i removed entire newslist class, redundant doing
i changed call in view controller following
var newsitems = [newsitem]() api.getlatestactivitydata({jsondata, error -> void in if (jsondata != nil) { dispatch_async(dispatch_get_main_queue(), { (_, subjson) in jsondata["data"] { let headline = subjson["headline"].string! let summary = subjson["summary"].string! let created = subjson["created"].string! let source = subjson["source"].string! let company = subjson["company"].string! let companylogo = subjson["companylogo"].string! let id = subjson["id"].int! newsitems.append(newsitem(headline: headline, summary: summary, created: created, source: source, company: company, companylogourl: companylogo, id: id)) } self.activitytableview.reloaddata() }) } else { print("api data fetch failed") print(error) } })
now should need once loop done, should able update table reload.
for 'newer' swift users me, didn't understand have helped know yesterday ... when call tableview.reloaddata() app trigger tabieview related events, if data source has been updated closure mine above, cellforrowatindexpath , numberofrowsinsection able correctly update. assign data in cellforrowatindexpath function.
hope helps someone!
Comments
Post a Comment