[英]Load and save struct into UserDefaults
I am trying to save the user in UserDefaults from a struct that fetches the data from an API when a user logs in successfully.我正在尝试将用户保存在 UserDefaults 中,该结构在用户成功登录时从 API 获取数据。
Here is my Webservice class:这是我的 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()
}
}
Here is my model class:这是我的模型类:
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
}
}
And here is my view model:这是我的视图模型:
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
}
}
This is how I am calling it:我是这样称呼它的:
let login = LoginUser(email: email, password: password)
let vm = UserViewModel(loginUser: login)
Webservice().load(resource: User.create(vm: vm), caller: self) { (result) in
My model and view model conform to Codable as well as my Resource is Codable too.我的模型和视图模型符合 Codable 以及我的 Resource 也是 Codable。
What is the reason of the error that T.type
does not conform to protocol Encodable? T.type
不符合Encodable协议的错误原因是什么? How to resolve it?如何解决?
Is this approach to send and receive data appropriate?这种发送和接收数据的方法是否合适?
You didn't specify that T
should be Encodable
for load(resource:...
function of class Webservice:
您没有指定
T
应该是Encodable
for load(resource:...
类Webservice:
函数Webservice:
Change this:改变这个:
class Webservice {
func load<T>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {
To this:对此:
class Webservice {
func load<T: Encodable>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {
And also you need to encode value, not generic type here:而且您还需要对值进行编码,而不是这里的泛型类型:
UserDefaults.standard.set(PropertyListEncoder().encode(T.self), forKey: "user")
should be应该
UserDefaults.standard.set(try PropertyListEncoder().encode(result), forKey: "user")
But another question is: Why do you encode from JSON and then encode it to PropertyList?但另一个问题是:为什么要从 JSON 编码,然后将其编码为 PropertyList? Why not save JSON data in UserDefaults?
为什么不在 UserDefaults 中保存 JSON 数据?
may be it will work for you.可能对你有用。
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
}}
this is how to store这是如何存储
func setCoableInUser<T: Codable>(_ object:T, key: String)-> Void{
UserDefaults.standard.save(object, forKey: key)}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.