将结构加载并保存到UserDefaults中

时间:2020-03-03 10:54:50

标签: ios swift xcode

我正在尝试通过用户成功登录后从API提取数据的结构将用户保存在UserDefaults中。

这是我的Web服务课程:

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不符合可编码协议的错误原因是什么?如何解决?

这种发送和接收数据的方法合适吗?

2 个答案:

答案 0 :(得分:3)

对于类T的{​​{1}}函数,您没有指定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) {

应该是

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

但是另一个问题是:为什么要从JSON编码然后将其编码到PropertyList?为什么不将JSON数据保存在UserDefaults中?

答案 1 :(得分:0)

也许对您有用。

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)}