Как я могу вернуть весь ответ от API на мое приложение Swift - PullRequest
1 голос
/ 26 февраля 2020

Я учусь быстро, и я вижу пример здесь https://matteomanferdini.com/network-requests-rest-apis-ios-swift/, и я пытаюсь изменить код для чего-то, что работает для меня.

так выглядит оригинальный код

struct Wrapper<T: Decodable>: Decodable {
    let items: [T]?
}


protocol NetworkRequest: AnyObject {
    associatedtype ModelType
    func decode(_ data: Data) -> ModelType?
    func load(withCompletion completion: @escaping (ModelType?) -> Void)
}

extension NetworkRequest {
    fileprivate func load(_ url: URLRequest, withCompletion completion: @escaping (ModelType?) -> Void) {
        let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
        let task = session.dataTask(with: url, completionHandler: { [weak self] (data: Data?, response: URLResponse?, error: Error?) -> Void in

            if let error = error {
                print("Error: \(error)")
            }

            guard let data = data else {
                completion(nil)
                return
            }

            completion(self?.decode(data))
        })
        task.resume()
    }
}

class APIRequest<Resource: APIResource> {
    let resource: Resource

    init(resource: Resource) {
        self.resource = resource
    }
}

extension APIRequest: NetworkRequest {
    func decode(_ data: Data) -> [Resource.ModelType]? {
        let wrapper = try? JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data)
        return wrapper?.items
    }

    func load(withCompletion completion: @escaping ([Resource.ModelType]?) -> Void) {
        load(resource.request, withCompletion: completion)
    }
}

но что мне нужно изменить структуру Wrapper на

struct Wrapper<T: Decodable>: Decodable {
    let items: [T]?
    let response: Bool?
    let message: String?
}

и вернуть items, response и message не только items

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Я изменяю код следующим образом

class NetworkRequest<Resource: APIResource> {

    let resource: Resource

    init(resource: Resource) {
        self.resource = resource
    }

    func load(withCompletion completion: @escaping (Result<Wrapper<Resource.ModelType>,Error>) -> Void) {
        let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
        let task = session.dataTask(with: self.resource.request) { data, _, error in
            if let error = error {
                completion(.failure(error))
            } else {
                completion( Result {try JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data!)})
            }
        }
        task.resume()
    }
}

struct LoginResource: APIResource {
    typealias ModelType = Token
    let methodPath = "/users/login/"
    let method = "post"
    var params: [String: Any]?

    init(username: String, password: String) {
        self.params = ["username":username, "password": password]
    }
}

На мой взгляд:

func login() {
        if user == "" || password == "" {
            self.title_alert = "Info"
            message_alert = "Test Alert"
            show_alert = true
            return
        }

        let loginRequest = NetworkRequest(resource: LoginResource(username:user,password:password))
        loginRequest.load { result in
            switch result {
                case .failure(let error):
                    print(error)
                case .success(let data):
                    print(data)
            }
        }

    }

Я не знаю, является ли это лучшим способом, но работает Спасибо @ vadian

0 голосов
/ 26 февраля 2020

В этом случае вам вообще не нужен протокол, потому что вы хотите получить объект root.

Этого достаточно

struct Wrapper<T: Decodable>: Decodable {
    let items: [T]
    let response: Bool
    let message: String
}

class NetworkRequest {
    func load<T : Decodable>(_ request: URLRequest, withCompletion completion: @escaping (Result<Wrapper<T>,Error>) -> Void) {
        let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
        let task = session.dataTask(with: request) { data, _, error in
            if let error = error {
                completion(.failure(error))
            } else {
                completion( Result {try JSONDecoder().decode(Wrapper<T>.self, from: data!)})
            }
        }
        task.resume()
    }
}

Обработчик завершения возвращает объект Result, в случае успеха объект-оболочка и при ошибке все ошибки.

В структуре оболочки объявите все свойства необязательными, чтобы получать сообщения об ошибках, и измените только те свойства на необязательные, которые действительно могут быть nil.

...