JSON转模型&归档与解档

JSON转模型&归档与解档,第1张

1.用户账户模型类 UserAccount.swift

///用户账户模型
class UserAccount: NSObject, NSCoding{
    //用户授权的唯一票据,用于调用微博的开放接口,同时也是第三方应用验证微博用户登录的唯一票据,第三方应用应该用该票据和自己应用内的用户建立唯一影射关系,来识别登录状态,不能使用本返回值里的UID字段来做登录识别。
    @objc var access_token: String?
    //access_token的生命周期,单位是秒数  TimeInterval = 0 /String?
    //一旦从服务器获得过期的时间,立刻计算准确的日期
    @objc var expires_in: TimeInterval = 0{
        didSet{
            //计算过期日期
            expiresDate = Date(timeIntervalSinceNow: expires_in)
        }
    }
    //过期日期
    @objc var expiresDate:Date?
    //授权用户的UID,本字段只是为了方便开发者,减少一次user/show接口调用而返回的,第三方应用不能用此字段作为用户登录状态的识别,只有access_token才是用户授权的唯一票据。
    @objc var uid: String?
    @objc var isRealName: Bool = false
    //用户昵称
    @objc var screen_name: String?
    //用户头像地址(大图),180×180像素
    @objc var avatar_large: String?
    
    init(dict:[String: Any]) {
        super.init()
        setValuesForKeys(dict)
    }
    
    override func setValue(_ value: Any?, forUndefinedKey key: String) {}
    
    //打印模型的描述信息
    override var description: String{
        let key = ["access_token", "expires_in", "expiresDate", "uid", "isRealName", "screen_name", "avatar_large"]
        return dictionaryWithValues(forKeys: key).description
    }
    
    //MARK: - "键值" 归档和解档
    /// 归档 - 把当前对象保存到磁盘前,将对象编码成二进制数据 - 跟网络的序列化概念很像
    /// - Parameter coder: 编码器
    func encode(with coder: NSCoder) {
        coder.encode(access_token, forKey: "access_token")
        coder.encode(expiresDate, forKey: "expiresDate")
        coder.encode(uid, forKey: "uid")
        coder.encode(screen_name, forKey: "screen_name")
        coder.encode(avatar_large, forKey: "avatar_large")
    }
    
    /// 接档 - 从磁盘加载二进制文件,转成对象时调用  - 跟网络的反序列化很像
    /// - Parameter coder: 解码器
    /// - required 当前对象
    ///  'required' -  当前没有继承性,所有的对象只能解档出当前的类对象
    required init?(coder: NSCoder) {
        access_token = coder.decodeObject(forKey: "access_token") as? String
        expiresDate =  coder.decodeObject(forKey: "expiresDate") as? Date
        uid = coder.decodeObject(forKey: "uid") as? String
        screen_name = coder.decodeObject(forKey: "screen_name") as? String
        avatar_large =  coder.decodeObject(forKey: "avatar_large")as? String
    }
}

// 在 extension 中只允许写 便利构造函数,不允许写指定的构造函数,
// 不能定义存储型属性,定义存储型属性,会破坏类本身的结构
extension UserAccount{
//    required init?(coder: NSCoder) {
//
//    }
}

2.测试返回数据内容 - AFN 默认的响应格式是 JSON,会直接反序列化

   func loadAccessToken(code: String, finished: @escaping requestCallBack){
        let urlString = "https://api.weibo.com/oauth2/access_token"
        let params : [String: Any] = ["client_id": appKey, "client_secret": appSecret, "grant_type":"authorization_code", "code": code, "redirect_uri": redirectUrl]
        //测试返回数据内容 - AFN 默认的响应格式是 JSON,会直接反序列化
        //如果要确认数据格式的问题
        //如果是 NSNumber,则没有引号,在做 KVC 指定属性类型非常重要
        //1>设置相应数据格式是二进制的
        responseSerializer = AFHTTPResponseSerializer()
        //2>发起网络请求
        post(urlString, parameters: params, headers: nil, progress: nil, success: { _, result in
            //将二进制数据转换成字符串
            let json = String(data: result as! Data, encoding: .utf8)
            print(json)
        }, failure: nil)
    }

3. JSON 转字典,字典转模型 调用函数

//JSON 字符串 -> 字典 -> 模型
    func jsonToDict(){
        let re = "{\"access_token\":\"2.00FdBF4*********13129a3d6Io4yB\",\"remind_in\":\"157679999\",\"expires_in\":157679999,\"uid\":\"30******31\",\"isRealName\":\"true\"}"
        guard let dict  = try? JSONSerialization.jsonObject(with: re.data(using: .utf8)!) else{
            print("转换失败")
            return
        }
        self.account = UserAccount(dict: dict as! [String: Any])
        print(self.account)
    }

4. 沙盒解档与归档
  4.1 声明参数

    ///用户模型
    var account: UserAccount?
    
    //归档文件保存路径
    private var accountURL: URL?{
        guard let documentURL = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first else {return nil}
        return documentURL.appendingPathComponent("account.plist")
    }
    
    /// 归档的保存路径 计算型属性 - 类似于有返回值的函数,调用的时候,语义更清晰
    /// 如果在 OC 中,可以通过只读属性 / 函数的方式实现
    private var accountPaths: String{
        let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
        return (path as NSString).appendingPathComponent("account.plist")
    } 

  4.2 归档保存对象

func dataToBaArchived(){
        //NSKeyedArchiver.archiveRootObject(account, toFile: self.accountPath)
        //保存对象  在实际开发中,一定要确认文件真的保存了  替代方法
        //执行此方法 - 会调用对象的 encode 方法
        guard let dataToBaArchived = try? NSKeyedArchiver.archivedData(withRootObject: account, requiringSecureCoding: false) else{
            print("解档数据失败")
            return
        }
        
        guard let _ =  try? dataToBaArchived.write(to: self.accountURL!) else{
            print("存储失败")
            return
        }
    }

  4.3 解档读取对象

func unarchiveWithData(){
        // 从沙盒中解档数据,恢复当前数据 - 磁盘读写的速度最慢,不如内存读写效率高
        // account = NSKeyedUnarchiver.unarchiveObject(withFile: accountPath) as? UserAccount
        if let archiverData = try? Data(contentsOf: accountURL!),
           let accountData = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archiverData)) as? UserAccount {
            account = accountData
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/993145.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存