URLSession.dataTask return 0的数据
URLSession.dataTask return the data with 0
我有一个网页以 JSON 格式提供服务器数据,我正在尝试访问该站点并获取这些对象。但是数据会 return with 0;空变量。我的代码是这样的。
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) {
(data, response, error) in
if error != nil {
print("Failed to download data")
}else {
let httpResponse = response as? HTTPURLResponse
print("data is like: \(data as! NSData)")
print(httpResponse)
self.data = data!
print("Data downloaded")
self.parseJSON(self.data)
}
}
task.resume()
}
func parseJSON(_ data: Data){
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as! NSArray
print(jsonResult)
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let forest = NSMutableArray()
for tree in 0 ..< jsonResult.count {
jsonElement = jsonResult[tree] as! NSDictionary
let tempTree = trees()
if let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkish_name"] as? String,
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String {
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
}
forest.add(tempTree)
}
DispatchQueue.main.async {
self.delegate.itemsDownloaded(items: forest)
}
}
我的主视图控制器就是这样
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
treeTableView.delegate = self
treeTableView.dataSource = self
let treeModel = trees()
treeModel.delegate = self
treeModel.downloadItems(completion: <#T##(Data?) -> Void#>)
}
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
当我进入网站时,JSON 对象就在这里。但是当我试图用 dataTask 检索对象时。数据将为 0。HTTP 响应也为 200。是否了解这种情况?谢谢,写得很好。
print(jsonResult) 是
{
"bothanical_prop" = "T\U00fcrkiyede park ve bah\U00e7elerde dekoratif ama\U00e7la kullan\U0131l\U0131r. Do\U011fal yay\U0131l\U0131\U015f alan\U0131 \U015eili'nin g\U00fcneyi ve G\U00fcnaybat\U0131 Arjantin'deki And Da\U011flar\U0131d\U0131r.";
"latin_name" = "Araucaria araucana (Molina) K. Koch.";
"leaf_type" = 1;
"seed_type" = 1;
"spreading_area" = "Do\U011fal alanlarda erkekler 15-18 m, di\U015filer ise 30-50 m ye kadar boylanabilir. Park ve bah\U00e7elerde ise 10 m'yi nadiren ge\U00e7en herdemye\U015fil a\U011fa\U00e7lard\U0131r. G\U00f6zvdesi d\U00fczg\U00fcnd\U00fcr; \U00f6zellikle gen\U00e7 bireyleri simetriktir ve konik formludur. Yapraklar\U0131, deri gibi sert, u\U0308\U00e7gen \U015feklinde, u\U00e7lar\U0131 sivri, bat\U0131c\U0131 ve her iki yu\U0308zu\U0308 koyu ye\U015fildir.";
"turkis_name" = "Maynum \U00c7\U0131kmaz A\U011fac\U0131";
},
{
"bothanical_prop" = "Norfolk adalar\U0131na (Avustralya) \U00f6zgu\U0308 endemik bir tu\U0308rdu\U0308r. Dekoratif ama\U00e7l\U0131 \U00fclkemizde Ege, Akdeniz ve Marmara \U00e7evresinde d\U0131\U00e7 mekan bitkisi olarak kullan\U0131l\U0131r.";
"latin_name" = "Araucaria heterophylla (Salisb.) Franco";
"leaf_type" = 1;
"seed_type" = 1;
"spreading_area" = "60-70 m\U2019ye kadar boylanabilen bir orman a\U011fac\U0131d\U0131r. Dallar g\U00f6vdeden 4-7\U2019li \U00e7evrel olarak \U00e7\U0131kar. G\U00f6vde kabu\U011fu ince levhalar halinde \U00e7atlakl\U0131d\U0131r. Yapraklar\U0131 2 farkl\U0131 \U015fekildedir: Gen\U00e7 ve yan su\U0308rgu\U0308nlerde a\U00e7\U0131k ye\U015fil, biz gibi uzun, k\U00f6\U015feli ve yumu\U015fak; ya\U015fl\U0131 su\U0308rgu\U0308nlerde ise daha k\U0131sa, daha sert, s\U0131k, birbiri u\U0308zerine binmi\U015f ve u\U00e7 k\U0131s\U0131mlar\U0131 boynuz gibi \U00f6ne do\U011fru k\U0131vr\U0131lm\U0131\U015f olan yapraklar vard\U0131r";
"turkis_name" = "Salon arokaryas\U0131";
}
如果你调用它然后期望 data
是非空的,你会失望的。 URLSession dataTask
是异步的。当 downloadItems()
函数 returns.
时,它不会读取您的数据
URLSession dataTask 是异步的,因此您必须进行回调才能获取数据。
以这种方式更改您的代码:
func downloadItems(completion: @escaping (_ result: Data?)->Void) {
let url: URL = URL(string: urlPath)!
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
completion(nil)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
// remove this
//self.data = data!
//print("Data downloaded")
//self.parseJSON(self.data)
//add this
guard let data = data else { return }
completion(data)
}
}
task.resume()
}
然后你可以通过这种方式在任何地方调用你的方法:
downloadItems{ data in
self.data = self.parseJSON(data)
}
编辑:
所以在你的情况下你必须改变这个:
treeModel.downloadItems(completion: <#T##(Data?) -> Void#>)
进入这个:
treeModel.downloadItems{ data in
feedTrees = self.parseJSON(data)
}
I say this because you're parseJSON function does return nothing, so I assume you're parseJSON is wrong
我会这样做:
NOTE: this function assume that your feedTrees is NSMutableArray
//Make your function return NSMutable array
func parseJSON(_ data: Data) -> NSMutableArray{
var jsonResult = NSArray()
//Put all of your code into do-catch
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
var jsonElement = NSDictionary()
let forest = NSMutableArray()
for tree in 0 ..< jsonResult.count {
jsonElement = jsonResult[tree] as! NSDictionary
let tempTree = trees()
if let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkish_name"] as? String,
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String {
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
//Add here your tree or it can be empty
forest.add(tempTree)
}
}
//AFTER THE LOOP
return forest
} catch let error as NSError {
print(error)
}
}
似乎你的 API returns turkis_name
而不是 turkish_name
:
"turkis_name" = "Maynum \U00c7\U0131kmaz A\U011fac\U0131";
告诉您的服务器端工程师修复它以遵循 API 规范。或者,是您误读了 API 规范?
无论如何,当您需要调整代码以适应实际响应时,您可能只需要修复一行。
let turkishName = jsonElement["turkis_name"] as? String,
但我给你一个实用的建议:
不要默默地忽略错误或无效输入。
通过一些修改使您的代码更加 Swifty,您的 parseJSON(_:)
将如下所示:
func parseJSON(_ data: Data) -> NSArray {
do{
guard let jsonResult = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
print("Invalid JSON structure")
return []
}
let forest = NSMutableArray()
for jsonElement in jsonResult {
if
let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkis_name"] as? String, //###Use the right key here
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String
{
let tempTree = trees()
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
forest.add(tempTree)
} else {
//### Do not ignore errors or invalid inputs silently.
print("Missing any of 'latin_name', 'turkis_name', 'seed_type', 'leaf_type', 'spreading_area', 'bothanical_prop'", jsonElement)
}
}
return forest
} catch let error {
print(error)
return []
}
}
(还有一些我想修复的部分,但是那些需要修改你代码的隐藏部分,所以我放弃了。并考虑采用Codable
,当使用JSON.)
您可能需要更多修复,但是当您写一些关于意外结果的内容时,请记住包括:
- 实际结果的具体输出
- 除了何时何地获得输出
- 和预期的结果
放置 print
语句并显示包含它的代码的输出将是一个好方法。
我修复了这个问题...修复前我的代码
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
self.treeTableView.delegate = self
self.treeTableView.dataSource = self
let treeModel = TreeModel()
treeModel.delegate = self
treeModel.downloadItems()
}
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
问题解决后
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
self.treeTableView.delegate = self
self.treeTableView.dataSource = self
let treeModel = TreeModel()
treeModel.delegate = self
treeModel.downloadItems()
}
只需将协议方法移到 viewDidLoad() 的顶部即可。
我有一个网页以 JSON 格式提供服务器数据,我正在尝试访问该站点并获取这些对象。但是数据会 return with 0;空变量。我的代码是这样的。
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) {
(data, response, error) in
if error != nil {
print("Failed to download data")
}else {
let httpResponse = response as? HTTPURLResponse
print("data is like: \(data as! NSData)")
print(httpResponse)
self.data = data!
print("Data downloaded")
self.parseJSON(self.data)
}
}
task.resume()
}
func parseJSON(_ data: Data){
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as! NSArray
print(jsonResult)
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let forest = NSMutableArray()
for tree in 0 ..< jsonResult.count {
jsonElement = jsonResult[tree] as! NSDictionary
let tempTree = trees()
if let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkish_name"] as? String,
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String {
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
}
forest.add(tempTree)
}
DispatchQueue.main.async {
self.delegate.itemsDownloaded(items: forest)
}
}
我的主视图控制器就是这样
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
treeTableView.delegate = self
treeTableView.dataSource = self
let treeModel = trees()
treeModel.delegate = self
treeModel.downloadItems(completion: <#T##(Data?) -> Void#>)
}
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
当我进入网站时,JSON 对象就在这里。但是当我试图用 dataTask 检索对象时。数据将为 0。HTTP 响应也为 200。是否了解这种情况?谢谢,写得很好。
print(jsonResult) 是
{
"bothanical_prop" = "T\U00fcrkiyede park ve bah\U00e7elerde dekoratif ama\U00e7la kullan\U0131l\U0131r. Do\U011fal yay\U0131l\U0131\U015f alan\U0131 \U015eili'nin g\U00fcneyi ve G\U00fcnaybat\U0131 Arjantin'deki And Da\U011flar\U0131d\U0131r.";
"latin_name" = "Araucaria araucana (Molina) K. Koch.";
"leaf_type" = 1;
"seed_type" = 1;
"spreading_area" = "Do\U011fal alanlarda erkekler 15-18 m, di\U015filer ise 30-50 m ye kadar boylanabilir. Park ve bah\U00e7elerde ise 10 m'yi nadiren ge\U00e7en herdemye\U015fil a\U011fa\U00e7lard\U0131r. G\U00f6zvdesi d\U00fczg\U00fcnd\U00fcr; \U00f6zellikle gen\U00e7 bireyleri simetriktir ve konik formludur. Yapraklar\U0131, deri gibi sert, u\U0308\U00e7gen \U015feklinde, u\U00e7lar\U0131 sivri, bat\U0131c\U0131 ve her iki yu\U0308zu\U0308 koyu ye\U015fildir.";
"turkis_name" = "Maynum \U00c7\U0131kmaz A\U011fac\U0131";
},
{
"bothanical_prop" = "Norfolk adalar\U0131na (Avustralya) \U00f6zgu\U0308 endemik bir tu\U0308rdu\U0308r. Dekoratif ama\U00e7l\U0131 \U00fclkemizde Ege, Akdeniz ve Marmara \U00e7evresinde d\U0131\U00e7 mekan bitkisi olarak kullan\U0131l\U0131r.";
"latin_name" = "Araucaria heterophylla (Salisb.) Franco";
"leaf_type" = 1;
"seed_type" = 1;
"spreading_area" = "60-70 m\U2019ye kadar boylanabilen bir orman a\U011fac\U0131d\U0131r. Dallar g\U00f6vdeden 4-7\U2019li \U00e7evrel olarak \U00e7\U0131kar. G\U00f6vde kabu\U011fu ince levhalar halinde \U00e7atlakl\U0131d\U0131r. Yapraklar\U0131 2 farkl\U0131 \U015fekildedir: Gen\U00e7 ve yan su\U0308rgu\U0308nlerde a\U00e7\U0131k ye\U015fil, biz gibi uzun, k\U00f6\U015feli ve yumu\U015fak; ya\U015fl\U0131 su\U0308rgu\U0308nlerde ise daha k\U0131sa, daha sert, s\U0131k, birbiri u\U0308zerine binmi\U015f ve u\U00e7 k\U0131s\U0131mlar\U0131 boynuz gibi \U00f6ne do\U011fru k\U0131vr\U0131lm\U0131\U015f olan yapraklar vard\U0131r";
"turkis_name" = "Salon arokaryas\U0131";
}
如果你调用它然后期望 data
是非空的,你会失望的。 URLSession dataTask
是异步的。当 downloadItems()
函数 returns.
URLSession dataTask 是异步的,因此您必须进行回调才能获取数据。
以这种方式更改您的代码:
func downloadItems(completion: @escaping (_ result: Data?)->Void) {
let url: URL = URL(string: urlPath)!
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
completion(nil)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
// remove this
//self.data = data!
//print("Data downloaded")
//self.parseJSON(self.data)
//add this
guard let data = data else { return }
completion(data)
}
}
task.resume()
}
然后你可以通过这种方式在任何地方调用你的方法:
downloadItems{ data in
self.data = self.parseJSON(data)
}
编辑: 所以在你的情况下你必须改变这个:
treeModel.downloadItems(completion: <#T##(Data?) -> Void#>)
进入这个:
treeModel.downloadItems{ data in
feedTrees = self.parseJSON(data)
}
I say this because you're parseJSON function does return nothing, so I assume you're parseJSON is wrong
我会这样做:
NOTE: this function assume that your feedTrees is NSMutableArray
//Make your function return NSMutable array
func parseJSON(_ data: Data) -> NSMutableArray{
var jsonResult = NSArray()
//Put all of your code into do-catch
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
var jsonElement = NSDictionary()
let forest = NSMutableArray()
for tree in 0 ..< jsonResult.count {
jsonElement = jsonResult[tree] as! NSDictionary
let tempTree = trees()
if let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkish_name"] as? String,
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String {
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
//Add here your tree or it can be empty
forest.add(tempTree)
}
}
//AFTER THE LOOP
return forest
} catch let error as NSError {
print(error)
}
}
似乎你的 API returns turkis_name
而不是 turkish_name
:
"turkis_name" = "Maynum \U00c7\U0131kmaz A\U011fac\U0131";
告诉您的服务器端工程师修复它以遵循 API 规范。或者,是您误读了 API 规范?
无论如何,当您需要调整代码以适应实际响应时,您可能只需要修复一行。
let turkishName = jsonElement["turkis_name"] as? String,
但我给你一个实用的建议:
不要默默地忽略错误或无效输入。
通过一些修改使您的代码更加 Swifty,您的 parseJSON(_:)
将如下所示:
func parseJSON(_ data: Data) -> NSArray {
do{
guard let jsonResult = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
print("Invalid JSON structure")
return []
}
let forest = NSMutableArray()
for jsonElement in jsonResult {
if
let latinName = jsonElement["latin_name"] as? String,
let turkishName = jsonElement["turkis_name"] as? String, //###Use the right key here
let seedType = jsonElement["seed_type"] as? Int,
let leafType = jsonElement["leaf_type"] as? Int,
let spreadingArea = jsonElement["spreading_area"] as? String,
let bothanicalProp = jsonElement["bothanical_prop"] as? String
{
let tempTree = trees()
tempTree.latin_name = latinName
tempTree.turkish_name = turkishName
tempTree.seed_type = seedType
tempTree.leaf_type = leafType
tempTree.spreading_area = spreadingArea
tempTree.botanical_prop = bothanicalProp
forest.add(tempTree)
} else {
//### Do not ignore errors or invalid inputs silently.
print("Missing any of 'latin_name', 'turkis_name', 'seed_type', 'leaf_type', 'spreading_area', 'bothanical_prop'", jsonElement)
}
}
return forest
} catch let error {
print(error)
return []
}
}
(还有一些我想修复的部分,但是那些需要修改你代码的隐藏部分,所以我放弃了。并考虑采用Codable
,当使用JSON.)
您可能需要更多修复,但是当您写一些关于意外结果的内容时,请记住包括:
- 实际结果的具体输出
- 除了何时何地获得输出
- 和预期的结果
放置 print
语句并显示包含它的代码的输出将是一个好方法。
我修复了这个问题...修复前我的代码
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
self.treeTableView.delegate = self
self.treeTableView.dataSource = self
let treeModel = TreeModel()
treeModel.delegate = self
treeModel.downloadItems()
}
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
问题解决后
func itemsDownloaded(items: NSArray) {
feedTrees = items
self.treeTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
//table view delegats and datasource declaration
self.treeTableView.delegate = self
self.treeTableView.dataSource = self
let treeModel = TreeModel()
treeModel.delegate = self
treeModel.downloadItems()
}
只需将协议方法移到 viewDidLoad() 的顶部即可。