Парсинг JSON и ошибка Unexpected non-void return value in void function


#1

Здравствуйте

Подскажите пожалуйста что я делаю не так?

Имеется класс NetworkService в котором создал метод класса:

    class func getCities(countryId: Int) -> [City] {

    // API link
    let urlString = "https://mylink.me/api/cities/\(countryId)/\(NetworkService().urlParamSecretKey)"
    
    //
    guard let url = URL(string: urlString) else { fatalError() }
    
    URLSession.shared.dataTask(with: url) { (data, _, _) in
        
        guard let data = data else { fatalError() }
    
        do {
            let decoder = JSONDecoder()
            return try decoder.decode([City].self, from: data)
            
        } catch {
            fatalError("Couldn't parse Json")
        }
        
    }.resume()
    
}

Ругаться на ошибку Unexpected non-void return value in void function

Хочу получить массив Городов

В структуре View вызываю

let citiesList: [City] = NetworkService.getCities(countryId: 114)

#2

потому что вы возвращаете значение не в функции, а в замыкании.
вам нужно использовать closure, для возврата данных. т.е. вам нужно создать свое замыкание в этой функции.


#3
    class func getCities(countryId: Int) {

    // API link
    let urlString = "https://link.me/api/cities/\(countryId)/\(NetworkService().urlKeyString)"
    
    var cities: [City]
    
    //
    guard let url = URL(string: urlString) else { fatalError() }
    
    
    URLSession.shared.dataTask(with: url) { (data, _, _) in
        
        guard let data = data else { fatalError() }
    
        do {
            let decoder = JSONDecoder()
            let cities = try decoder.decode([City].self, from: data)
            
        } catch {
            fatalError()
        }
        
    }.resume()
    
}

Не могу понять как положить данные в переменную cities из клоужера


#4

#5

Это я уже 100 раз перечитал ) на практике что то много вопросов )
Я совсем начинающий, простите за глупые вопросы


#6

Получается мне нужно еще в class func добавить CompletionHandler и захватить (получить ) данные уже в самой view ?


#7

замыкание - это параметр, который передается в функцию как и любые другие, за исключением того, что замыкание имеет свой тип.

func myFunc(param: Any, closure: () -> ()) {}

замыкания так же могут принимать какие-то свои параметры, но и могут возвращать.

func myFunc(param: Any, closure: () -> (Any)) {
    // используется просто
    URLSession.task...() { data, ... in
         // получаете свои данные и передаете в ваше замыкание
         closure(myData)
    }
}

использование такой функции аналогично тому, как вы используете URLSession

NetworkService.getCities(...) { cities in
    // делаете что нужно со списком городов
}

Если где-то перепутал порядок или синтаксис, извиняюсь, сижу пока на андроиде несколько месяцев.


#8

Все равно не получается

    class func getCities(countryId: Int, completion: @escaping (_ cities: [City])->()) {

    // API link
    let urlString = "https://link.me/api/cities/\(countryId)/\(NetworkService().urlKeyString)"
    
    guard let url = URL(string: urlString) else { fatalError() }
    
    URLSession.shared.dataTask(with: url) { (data, _, _) in
        
        guard let data = data else { fatalError() }
    
        do {
            let decoder = JSONDecoder()
            let cities = try decoder.decode([City].self, from: data)
            
            completion(cities)
            
        } catch {
            fatalError()
        }
        
    }.resume()
    
}

и пытаюсь данные получить

import SwiftUI

struct CitiesView: View {

//    let response = NetworkService.getCities(countryId: 114)

let result = NetworkService.getCities(countryId: 114) { (city) in
    
    let cities:[City] = city
}


var body: some View {
    Text("\(cities.name)")
}
}

struct CitiesView_Previews: PreviewProvider {
static var previews: some View {
    CitiesView()
}
}

#9

В общем задача у меня такая:

использую Swift 5 + SwiftUI

По ссылке у меня доступны данные в формате json

[
{

“id”: 61591,
“name”: “Прага”,
“name_en”: “Prague”,
“airport”: true,
“priority”: 342
},
{
“id”: 157441,
“name”: “Бероун”,
“name_en”: “Beroun”,
“airport”: false,
“priority”: 11
},
{
“id”: 239311,
“name”: “Божи-Дар”,
“name_en”: “Bozi Dar”,
“airport”: false,
“priority”: 23
},
{
“id”: 86561,
“name”: “Брно”,
“name_en”: “Brno”,
“airport”: false,
“priority”: 36
}
]

Я создал в группе Model Структуру City

struct City: Codable, Identifiable, Hashable  {

let id:Int
let name: String
let name_en:String
let airport:Bool
let priority:Int

}

Создал класс NetworkService и в нем class func что не создавая экземпляр класса получить список городов:

    class func getCities(countryId: Int, completion: @escaping (_ cities: [City])->()) {

    // API link
    let urlString = "https://link.me/api/cities/\(countryId)/\(NetworkService().urlKeyString)"
    
    guard let url = URL(string: urlString) else { fatalError() }
    
    URLSession.shared.dataTask(with: url) { (data, _, _) in
        
        guard let data = data else { fatalError() }
    
        do {
            let decoder = JSONDecoder()
            let cities = try decoder.decode([City].self, from: data)
            
            completion(cities)
            
        } catch {
            fatalError()
        }
        
    }.resume()
    
}

И хочу получить их в cityView

struct CitiesView: View {

//    let response = NetworkService.getCities(countryId: 114)

let result = NetworkService.getCities(countryId: 114) { (city) in
    
    let cities:[City] = city
}


var body: some View {
    Text("\(cities.name)")
}
}

struct CitiesView_Previews: PreviewProvider {
static var previews: some View {
    CitiesView()
}
}

Получить их нужно по индикатору страны Int

 let cities:[City] = NetworkService.getCities(countryId: 114)

#10

пытаюсь сделать как в примере apple где данные загружаются в переменную

let landmarkData: [Landmark] = load("landmarkData.json")

func load<T: Decodable>(_ filename: String) -> T {
let data: Data

guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
    fatalError("Couldn't find \(filename) in main bundle.")
}

do {
    data = try Data(contentsOf: file)
} catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}

do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self, from: data)
} catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}

И потом мы просто получаем их во View

struct LandmarkRow: View {
var landmark: Landmark

var body: some View {
    HStack {
        landmark.image
            .resizable()
            .frame(width: 50, height: 50)
        Text(verbatim: landmark.name)
        Spacer()

        if landmark.isFavorite {
            Image(systemName: "star.fill")
                .imageScale(.medium)
                .foregroundColor(.yellow)
        }
    }
}
}

struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
    Group {
        LandmarkRow(landmark: landmarkData[0])
        LandmarkRow(landmark: landmarkData[1])
    }
    .previewLayout(.fixed(width: 300, height: 70))
}
}

#11
  1. в примере Apple не используется http запрос
  2. у вас проблема с областью видимости переменных
  3. что вы будете показывать во время запроса, т.к. данных у вас еще нет

#12

Буду очень благодарен если покажете на примере как получить данные и вывести список во view


#13

К сожалению нету столько времени вникать и писать код.
Но в гугле можно легко найти примеры.
Вроде как даже на ютубе Пархоменко Алксей делал подобное, если не ошибаюсь.


#14

Я уже если честно неделю пытаюсь во всем этом разобраться. Поэтому и зарегестрировался на форуме. В google первым делом полез искать, но там много старых примеров. В общем попробую сейчас поискать Пархоменко Алксей


#15

SwiftUI конечно классно, но неплохо было бы для начала научитсяь делать это на UIKit.


#16

не вижу смысла учить то что скоро уйдет, за swiftUI будущее


#17

вот от этого и ваше непонимание…
вы базовые вещи не понимаете, но сразу хотите продвинутое понять.
у вас ведь не только проблемы с получением данных.
я видел у вас проблемы с обалстью видимости переменных, так же есть логические проблемы, но это не страшно, придет с опытом.
не нужно сразу учиться прыгать далеко, научитесь прыгать на маленькие расстояния.


#18

вот канал на ютуб, ищите там получение данных


#19

Спасибо. Я купил доступ к курсам и все пересмотрел. Да я меня вообще опыта нет. Вот пробую писать но что то ничего не выходит.


#20

как-то вы быстро проскочили базовые уроки. стоило бы на них задержаться.