iOS 中数据的高效解档和归档

本文介绍了一种利用iOS的runtime机制动态为类添加NSCoding协议的方法,从而实现了对自定义类的自动归档和解档,简化了数据存储过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

  在iOS中数据的存储,无论是存储数据库(sqlite  支持的数据类型有五种NULL,整形(INT),浮点型(REAL)文本字符串(TEXT),二进制数据(BLOB) )还是存放在keychain , 或者是本地 plist 的文件 ,数据都以NSData(二进制数据)进行存储比较好,这样就牵扯到我们每定义一个新的类型,如果该数据需要义二进制数据进行存储时,必须进行归档和解档 ,每一次都要每定义一个新类都要进行一次归档和解档的书写,那有没有通用的办法呢?

解决方案

 上面的问题我们使用runtime来解决,在运行时,动态的获取该类是否遵循NSCoding 协议,动态的遵循该协议,并实现该协议的归档解档方法,如题流程如图:


如题代码如下: 

利用runtime动态为一个类添加NSCoding协议和NSCoding协议对应的方法

  • + (void)addCodingProtocolToObject:(Class )class
  • {
  •       SEL  encodeSEL = @selector(encodeWithCoder:);
  •       SEL  decoderSEL = @selector(initWithCoder:);
  •   [DataManager addProtocol:@"NSCoding" toClass:class];
  •   Class destClass = [DataManager class];
  •   [DataManager addProtocolMethod:encodeSEL withClass:destClass toClass:class];
  •   [DataManager addProtocolMethod:decoderSEL withClass:destClass toClass:class];
  • } 

利用runtime 动态的判断某一个类是否遵循了某一个协议方法,如果没有遵循,则动态的遵循

  • + (void)addProtocol:(NSString *)protocolName toClass:(Class)class
  • {
  •     if([protocolName hasPrefix:@"<"])
  •     {
  •         protocolName = [protocolName substringWithRange:NSMakeRange(1, protocolName.length-2)];
  •     }
  •     const char  *name = [protocolName UTF8String];
  •     Protocol *instanceProtocol = objc_getProtocol(name);
  •     if(instanceProtocol)
  •     {
  •         if(class_conformsToProtocol(class, instanceProtocol))
  •          {
  •               return;
  •          }
  •     }else
  •     {
  •         instanceProtocol = objc_allocateProtocol(name);
  •         objc_registerProtocol(instanceProtocol);
  •     }
  •     class_addProtocol(class, instanceProtocol);
  • }

利用 runtime  动态为某一个类添加另一个类的某一个方法

  • + (void)addProtocolMethod:(SEL)protocolSEL withClass:(Class)selClass toClass:(Class)toClass
  • {      
  •     Method  protocolMethod = class_getInstanceMethod(selClass,protocolSEL);
  •     IMP    protocolIMP = method_getImplementation(protocolMethod);
  •     const char *protocolTypes = method_getTypeEncoding(protocolMethod);
  •     if(!class_addMethod(toClass, protocolSEL, protocolIMP, protocolTypes))
  •     {
  •         class_replaceMethod(toClass, protocolSEL, protocolIMP, protocolTypes);
  •     }
  • }

利用runtime 动态的获取某一个类属性,包括继承自父类的属性,进行归档

  • - (void)encodeWithCoder:(NSCoder *)aCoder {
  •     Class selfClass = self.class;
  •     while (selfClass &&selfClass != [NSObject class]) {
  •         unsigned int outCount = 0;
  •         Ivar *ivars = class_copyIvarList([selfClass class], &outCount);
  •         for (int i = 0; i < outCount; i++) {
  •        
  •             Ivar ivar = ivars[i];
  •             const char *name = ivar_getName(ivar);
  •             NSString *key = [NSString stringWithUTF8String:name];
  •             id value = [self valueForKeyPath:key];
  •             [aCoder encodeObject:value forKey:key];
  •         }
  •         free(ivars);
  •         selfClass = [selfClass superclass];
  •     }
  • }

利用runtime 动态的获取某一个类的属性,包括继承自父类的属性,进行解档

  • - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  •     Class selfClass = self.class;
  •     while (selfClass &&selfClass != [NSObject class]) {
  •         unsigned int outCount = 0;
  •         Ivar *ivars = class_copyIvarList(selfClass, &outCount);
  •         for (int i = 0; i < outCount; i++) {
  •             Ivar ivar = ivars[i];
  •             NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
  •             id value = [aDecoder decodeObjectForKey:key];
  •             [self setValue:value forKey:key];
  •         }
  •         free(ivars);
  •         selfClass = [selfClass superclass];
  •     }
  •     return self;
  • }

优点: 

       以后对任何一个对象转化为NSData 进行存储和传输时,不用每次去手动的实现归档和解档,只用调用该方法即可

+ (void)addCodingProtocolToObject:(Class )class  传入类名

限制: 

     由于归档解档本身不支持可变的集合进行转化为二进制数据存储,所以改方案也不支持可变的集合 NSMutableArray  NSMutableDictionary的类的归档和解档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值