NSCoding & Codable & NSKeyedArchiver

缓存符合NSCoding协议的任意对象
- (void)encodeWithCoder:(NSCoder *)coder;
- (nullable instancetype)initWithCoder:(NSCoder *)coder; // NS_DESIGNATED_INITIALIZER
example
override func encode(with coder: NSCoder) {
  super.encode(with: coder)
}

required init?(coder: NSCoder) {
  super.init(coder: coder)
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
  super.init(nibName: nibNameOrNil, bundle: nil)
}

convenience init() {
  self.init(nibName: nil, bundle: nil)
}

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  if YAuth.isLoggedIn {
    interactor.getMessageCount()
  }
  if let libraryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).last {
    let directory = libraryPath + "/archiver_directory"
    if !FileManager.default.fileExists(atPath: directory) {
      try? FileManager.default.createDirectory(atPath: directory, withIntermediateDirectories: true, attributes: nil)
    }
    let data = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWith: data)
    archiver.encode(UIViewController(), forKey: "archiver_key")
    archiver.finishEncoding()
    data.write(to: URL.init(fileURLWithPath: directory + "/file_name"), atomically: true)
  }
  
  GCDQueue.executeInMainQueue({
    if let libraryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).last {
      let directory = libraryPath + "/archiver_directory"
      if let data = NSData(contentsOfFile: directory + "/file_name") as Data? {
        let unarchiver =  NSKeyedUnarchiver.init(forReadingWith: data)
        if let vc = unarchiver.decodeObject(forKey: "archiver_key") as? UIViewController {
          self.present(vc, animated: true, completion: nil)
        }
      }
    }
  }, afterDelay: .seconds(10))
}

Codable协议

typealias Codable = Decodable & Encodable

public protocol Decodable {
    init(from decoder: Decoder) throws
}

public protocol Encodable {
    func encode(to encoder: Encoder) throws
}

JSONEncoder

struct GroceryProduct: Codable {
  var name: String
  var points: Int
  var description: String?
}

let pear = GroceryProduct(name: "Pear", points: 250, description: "A ripe pear.")

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let data = try encoder.encode(pear)
print(String(data: data, encoding: .utf8)!)

/* Prints:
 {
   "name" : "Pear",
   "points" : 250,
   "description" : "A ripe pear."
 }
*/

JSONDecoder

struct GroceryProduct: Codable {
   var name: String
   var points: Int
  var description: String?
}
let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)

print(product.name) // Prints "Durian"

自定义嵌入键

class User: Codable {
  
  var name: String?
  
  // 自定义嵌入键
  enum CodingKeys: String, CodingKey {
    case memberName
  }
  
  required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .memberName)
  }
  
  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(name, forKey: .memberName)
  }

  init() {
    
  }
}

let jsonData = """
{
  "memberName": "Janine",
}
""".data(using: .utf8)!


func test() {
  do {
    let user = try? JSONDecoder().decode(User.self, from: jsonData)
    let data = try? JSONEncoder().encode(user)
    print(user.debugDescription)
    print(data?.description)
  } catch {
    print(error.localizedDescription)
  }
}

NSCoding & NSKeyedArchiver & Data Parsing

#import "DataModel.h"
#import <objc/runtime.h>

@implementation DataModel

- (NSArray *)getAllPropertyNames       //获取类的所有属性名称
{
    u_int count;
    objc_property_t *properties  =class_copyPropertyList([self class], &count);
    NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        const char* propertyName =property_getName(properties[i]);
        [propertiesArray addObject: [NSString stringWithUTF8String: propertyName]];
    }
    free(properties);
    return propertiesArray;
}

- (id)bundingData:(NSDictionary *)dict{          //绑定数据
    static Class oldClass;
    if ([self class]!=oldClass) {
        DLog(@"   >>>>>>>  绑定模型 >>>>>>>>>> : %@\n\n",[self class]);
        oldClass = [self class];
    }
    if (dict==nil) {
        return nil;
    }
    NSArray *propertyNames = [self getAllPropertyNames];
    for (NSString *key in propertyNames) {
        id value = nil;
        if ([key isEqualToString:@"pid"]) {
            value = [dict objectForKeyOrNil:@"id"];
        }else{
            value = [dict objectForKeyOrNil:key];
        }
        if (value) {
            [self setValue:value forKey:key];   //使用KVC给属性赋值
        }
    }
    return self;
}

- (NSDictionary *)toDictionary{
    NSArray *propertyKeyArray = [self getAllPropertyNames];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    for (NSString *key in propertyKeyArray) {
        id obj = SafeObj([self valueForKey:key]);
        //对象为空则不转换到Dictionary中
        if ((NSNull *)obj == [NSNull null]) {
            continue;
        }
        if ([key isEqualToString:@"pid"]) {
            [dict setObject:obj forKey:@"id"];
        }else{
            [dict setObject:obj forKey:key];
        }
    }
    return dict;
}

- (void)clearData{          //清除对象的值
    //   DLog(@"%@",self);                   //输出调试信息
    NSArray *propertyNames = [self getAllPropertyNames];
    for (NSString *key in propertyNames) {
        [self setValue:[NSNull null] forKey:key];   //使用KVC给属性赋值,清除对象的值
    }
    DLog(@"清除类 ------ > %@ (%@)",NSStringFromClass([self class]),self);
}


- (NSString *)description               //类描述方法
{
    NSMutableString *desc = [NSMutableString string];
    [desc appendString:@"\n\n"];
    [desc appendFormat:@"Class name: %@\n", NSStringFromClass([self class])];
    NSArray *propertyNames = [self getAllPropertyNames];
    for (NSString *key in propertyNames) {
        [desc appendFormat: @"%@: %@\n", key, [self valueForKey:key]];
    }
    return [NSString stringWithString:desc];
}


#pragma -mark 对象归档协议<NSCoding>方法
- (void)encodeWithCoder:(NSCoder *)encoder {
    NSArray *propertyNames = [self getAllPropertyNames];
    for (NSString *key in propertyNames) {
        [encoder encodeObject:[self valueForKey:key] forKey:key];
    }
}

- (id)initWithCoder:(NSCoder *)decoder {
    NSArray *propertyNames = [self getAllPropertyNames];
    for (NSString *key in propertyNames) {
        [self setValue:[decoder decodeObjectForKey:key] forKey:key] ;
    }
    return self;
}

#pragma -mark 对象归档
- (void)archiverToFile:(NSString *)fileName{                        //对象归档保存
    NSString *fullPath = [self getDocumentsPath:fileName];
    [NSKeyedArchiver archiveRootObject:self toFile:fullPath];
}

- (id)unArchiverFromFile:(NSString *)fileName{                      //反归档对象
    NSString *fullPath = [self getDocumentsPath:fileName];
    if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
        DataModel *model = [NSKeyedUnarchiver unarchiveObjectWithFile: fullPath];
        return model;
    }else{
        return nil;
    }
}
#pragma -mark 辅助方法
- (NSString *)getDocumentsPath:(NSString *)fileName{          //获取文档目录
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docPath = [paths objectAtIndex:0];
    return [docPath stringByAppendingPathComponent:fileName];
}

@end
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 前面文章中 UserDefaults 的基本用法 中对UserDefaults 进行了简单的介绍,它可以将一些简单...
    JamesSawyer阅读 4,465评论 2 12
  • Google question: what is keyed decoding container 翻译自: ht...
    ngugg阅读 604评论 0 1
  • 缓存 在众多可以本地保存数据的技术中,有三种脱颖而出:URL缓存、数据模型缓存(利用NSKeyedArchiver...
    hui8685291阅读 898评论 0 1
  • 为什么要有缓存 应用需要离线工作的主要原因就是改善应用所表现出的性能。将应用内容缓存起来就可以支持离线。我们可以用...
    milk_powder阅读 2,829评论 6 24
  • 偶尔当心如水面 平静如冰 坐在风景之外看个不停 惧怕摩天大楼阻挡住天空 怎么走也走不到应该去的地方 石子入水 波动...
    伍丁零阅读 291评论 0 7