我为我的描述简单而道歉,我是Swift作为一种语言的新手。
我有一个REST api,它为我的应用程序提供了所有数据。我试图从JSON提要填充表视图。从本质上讲,我正在努力坚持我在Web开发中使用的MVC模式。所以我构建了一个数据对象模型,然后是一个列表模型来包含该对象的各个实例。
然而,实际问题是,当我启动整个过程(最后一个代码示例)时,结果计数为0,但这仅仅是因为API调用的数据响应尚未发生。我宁愿不使用同步通话,但我觉得这是我解决这个问题的唯一方法,除非我开始将我的API调用直接打到控制器本身?
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")!
}
}
}
然后我有了我的NewsList类,它实际上使用闭包来构建一个新闻项数组。
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) {
for (_, 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)
}
}
对于上面的调用,我在RemoteAPI类中有以下方法
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()
}
要实际启动整个上述复杂的过程,我在视图控制器中有这个
var newsItems: [NewsItem] {
var newsList = NewsList.getNewsItems()
return newsList[0].newsItems
}
这是我们的痛点。如果我在上述调用之后触发print(newsItems.count)
,则结果为0.但是在一两秒之后,回调处理程序将实际接收数据并开始将项目分配给newsList
数组。
在实际接收数据之前,如何阻止数组分配?我是否只是以完全错误的方式解决这个问题?
XCODE 7 + Swift 2.0 + iOS 9.0.x
答案 0 :(得分:0)
我的错误在于我如何使用闭包。我依赖于我的闭包来在闭包之外分配值,然后在完成处理程序中返回这些值。
<强>解决方案:强>
我删除了整个NewsList类,它实际上是多余的我正在做的事情
我在视图控制器中更改了调用以执行以下操作
var newsItems = [NewsItem]()
api.getLatestActivityData({JSONData, error -> Void in
if (JSONData != nil) {
dispatch_async(dispatch_get_main_queue(), {
for (_, 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)
}
})
现在我需要做的就是一旦for循环完成,我应该可以通过重新加载来更新表。
对于像我这样的'新'快速用户,我不明白哪些会帮助知道昨天...当你拨打tableView.reloadData()
时,该应用会触发所有与tabieView相关的事件,如果你的数据我的cellForRowAtIndexPath
和numberOfRowsInSection
将能够正确更新,因此已从封闭更新源代码。只需在cellForRowAtIndexPath
功能中分配您的数据。
希望这有助于某人!