Загрузить и сохранить структуру в UserDefaults - PullRequest
0 голосов
/ 03 марта 2020

Я пытаюсь сохранить пользователя в UserDefaults из структуры, которая извлекает данные из API при успешном входе пользователя в систему.

Вот мой класс Webservice:

import Foundation
import UIKit

struct Resource<T: Codable> {

    let url : URL
    let httpMethod = HTTPMethod.post
    var body : Data? = nil
}

extension Resource {

    init(url: URL) {
        self.url = url
    }

}



enum HTTPMethod : String {
    case get = "GET"
    case post = "POST"
}

 enum NetworkingError: Error {
        case domainError
        case badResponse
        case encodingError
        case decodingError
    }


class Webservice {

    func load<T>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {

            var request = URLRequest(url: resource.url)
            request.httpMethod = resource.httpMethod.rawValue
            request.httpBody = resource.body
            request.addValue("application/JSON", forHTTPHeaderField: "Content-Type")

            URLSession.shared.dataTask(with: request) { (data, response, error) in


                guard let data = data, error == nil else {
                    return completion(.failure(.domainError))
                }

                let json = try? JSONSerialization.jsonObject(with: data, options: [])
                print(json)

                do {
                let result = try JSONDecoder().decode(T.self, from: data)

//save to UserDefaults

                    UserDefaults.standard.set(PropertyListEncoder().encode(T), forKey: "user")\\ here I am getting error that T.type does not conform to Encodable protocol.





completion(.success(result))


                }catch {


                    do {

                        if let result = try? JSONDecoder().decode(LoginErrorResponse.self, from: data){
                    print(result.errors.msg)
                        DispatchQueue.main.async {

                            let alert = AlertService().alert(message: "\(result.errors.msg[0])")
                            caller.present(alert, animated: true)

                        }
                        completion(.failure(.decodingError))
                    }

                        if let result = try? JSONDecoder().decode(SignUpErrorResponse.self, from: data){
                        print(result.errors.msg)
                            DispatchQueue.main.async {

                                let alert = AlertService().alert(message: "\(result.errors.msg)")
                                caller.present(alert, animated: true)

                            }
                            completion(.failure(.decodingError))
                        }

                }

            }





            }.resume()


        }

    }

Вот мой класс модели:

import Foundation

struct User: Encodable, Decodable {

    let name: String
    let email: String
    let password: String
    let first_name: String
    let last_name: String
}

extension User {

    static var all : Resource<User> = {

        guard let url = URL(string: "http://orderahead.gagzweblab.xyz:3001/login") else {
                    fatalError("url is incorrect")
               }
        return Resource<User>(url: url)

    }()

    static func create(vm : UserViewModel) -> Resource<UserResponseModel?> {

        let user = User(vm)
        guard let url = URL(string: "http://orderahead.gagzweblab.xyz:3001/register") else {
             fatalError("url is incorrect")
        }
        guard let data = try? JSONEncoder().encode(user) else {
             fatalError("error encoding user")
        }

        var resource = Resource<UserResponseModel?>(url: url)
        resource.body = data

        return resource
    }

}

extension User {

    init?(_ vm: UserViewModel) {

         let email = vm.email
         let password = vm.password
        let first_name = vm.first_name
        let last_name = vm.last_name
        let name = vm.name

        self.password = password
        self.email = email
        self.first_name = first_name
        self.last_name = last_name
        self.name = name
    }
}

А вот мой вид модели:

import Foundation

struct UserViewModel : Codable {
    let user : User

}

extension UserViewModel {

    var name : String {
        return self.user.name
    }
    var email : String {
        return self.user.email
    }
    var password : String {
        self.user.password
    }
    var first_name: String {
        self.user.first_name
    }
    var last_name: String {
        self.user.last_name
    }

}

Вот как я это называю:

let login = LoginUser(email: email, password: password)
                   let vm = UserViewModel(loginUser: login)

Webservice().load(resource: User.create(vm: vm), caller: self) { (result) in

Моя модель и модель представления соответствует Codable, а мой ресурс тоже Codable.

В чем причина ошибки, что T.type не соответствует протоколу Encodable? Как решить это?

Является ли этот подход для отправки и получения данных уместным?

Ответы [ 2 ]

3 голосов
/ 03 марта 2020

Вы не указали, что T должно быть Encodable для load(resource:... функции класса Webservice:

Измените это:

class Webservice {

  func load<T>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {

На это:

class Webservice {

  func load<T: Encodable>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {

А также вам нужно кодировать значение, а не generi c введите здесь:

UserDefaults.standard.set(PropertyListEncoder().encode(T.self), forKey: "user")

должно быть

UserDefaults.standard.set(try PropertyListEncoder().encode(result), forKey: "user")

Но другой вопрос: почему Вы кодируете из JSON, а затем кодируете его в PropertyList? Почему бы не сохранить JSON данные в UserDefaults?

0 голосов
/ 03 марта 2020

может быть, это будет работать для вас.

extension UserDefaults {

func save<T: Codable>(_ object: T, forKey key: String) {
    let encoder = JSONEncoder()
    if let encodedObject = try? encoder.encode(object) {
        UserDefaults.standard.set(encodedObject, forKey: key)
        UserDefaults.standard.synchronize()
    }
}

func getObject<T: Codable>(forKey key: String) -> T? {
    if let object = UserDefaults.standard.object(forKey: key) as? Data {
        let decoder = JSONDecoder()
        if let decodedObject = try? decoder.decode(T.self, from: object) {
            return decodedObject
        }
    }
    return nil
}}

это как хранить

func setCoableInUser<T: Codable>(_ object:T, key: String)-> Void{
UserDefaults.standard.save(object, forKey: key)}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...