美文网首页
归档archive

归档archive

作者: 喵喵粉 | 来源:发表于2020-07-02 11:43 被阅读0次

    更新swift版本

    fileprivate let filePath: String = {
            
            ///每个账号对应一个文件
            let path = NSTemporaryDirectory() + "\(kUserInfo.userId)-history.hs"
            
            return path
        }()
    
    • 加载
    func loadHistory() {
            
            if #available(iOS 11.0, *) {
                let url = URL(fileURLWithPath: filePath)
                
                guard let data = try? Data(contentsOf: url) else {
                    return
                }
                
                guard let list = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [String] else {
                    DebugLog("加载历史记录失败")
                    return
                }
                DebugLog(list)
                lists = list
            } else {
                guard let list = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? [String] else {
                    DebugLog("加载历史记录失败")
                    return
                }
                DebugLog(list)
                lists = list
            }
        }
    
    • 保存
    fileprivate func saveAction() -> Bool {
            if #available(iOS 11.0, *) {
                guard let data = try? NSKeyedArchiver.archivedData(withRootObject: lists, requiringSecureCoding: false) else {
                    return false
                }
                
                let url = URL(fileURLWithPath: filePath)
                
                guard ((try? data.write(to: url)) != nil) else { return false }
            }
            return NSKeyedArchiver.archiveRootObject(lists, toFile: filePath)
        }
    

    自定义对象的归档,使用iOS11API

    +archivedDataWithRootObject:requiringSecureCoding:error:
    +unarchivedObjectOfClasses:fromData:error:
    +unarchivedObjectOfClass:fromData:error:
    

    自定义类Book,遵守NSSecureCoding协议

    • Book.h
    @interface Book : NSObject<NSSecureCoding>
    
    @property (nonatomic, strong) NSString *bookName;
    
    @end
    

    实现supportsSecureCoding、- initWithCoder:、 -encodeWithCoder:方法

    supportsSecureCoding
    + (BOOL)supportsSecureCoding {
        return YES;
    }
    
    - (id)initWithCoder:(NSCoder *)coder { ... }
    - (void)encodeWithCoder:(NSCoder *)coder { ... }
    
    • Book.m
      SERIALIZER_CODER_DECODER宏贴在末尾
    #import "Book.h"
    #import "Runtime+CoderDeCoder.h"
    
    @implementation Book
    
    SERIALIZER_CODER_DECODER
    
    @end
    

    1. 单个Book对象的归档

    Book *book = [Book new];
    book.bookName = @"book";
        
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:book requiringSecureCoding:NO error:nil];
    Book *unarchiverBook = [NSKeyedUnarchiver unarchivedObjectOfClass:[Book class] fromData:data error:nil];
    

    2. Book数组的归档

    当修改数组的Book对象时,归档的数据不会受到影响

    Book *book1 = [Book new];
    book1.bookName = @"book1";
    
    Book *book2 = [Book new];
    book2.bookName = @"book2";
    
    NSArray *books = @[book1, book2];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:books requiringSecureCoding:NO error:nil];
    
    //修改book2
    Book *nb = books.lastObject;
    nb.bookName = @"new bookName 2";
    
    //打印原来的books
    for (Book *book in books) {
        NSLog(@"1---%@", book.bookName);
    }
    
    NSArray *unarchivers = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[Book.class, NSArray.class]] fromData:data error:nil];
    
    //打印解档的books
    for (Book *book in unarchivers) {
        NSLog(@"2---%@", book.bookName);
    }
    

    打印结果

    1---book1
    1---new bookName 2 //数据变动
    2---book1
    2---book2  //数据未变
    

    3. Book字典的归档

    - (void)dictionaryDemo {
        Book *book1 = [Book new];
        book1.bookName = @"book1";
        Book *book2 = [Book new];
        book2.bookName = @"book2";
        
        //1. 原始数据
        NSDictionary *dic = @{@"a": book1, @"b": book2};
        for (Book *book in dic.allValues) {
            NSLog(@"1---%@", book.bookName);
        }
        
        //2.归档
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dic requiringSecureCoding:NO error:nil];
        
        //3.修改原始数据
        Book *nb = dic.allValues.lastObject;
        nb.bookName = @"new bookName";
        
        for (Book *book in dic.allValues) {
            NSLog(@"2---%@", book.bookName);
        }
        
        //4.解档
        NSDictionary *unarchiver = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[Book.class, NSDictionary.class]] fromData:data error:nil];
        for (Book *book in unarchiver.allValues) {
            NSLog(@"3---%@", book.bookName);
        }
    }
    
    • 打印
    1---book1
    1---book2
    2---book1
    2---new bookName
    3---book1
    3---book2
    

    4. 非自定义对象的归档

    NSArray *strings = @[@"book1", @"book2"];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:strings requiringSecureCoding:NO error:nil];
    NSArray *unarchiverStrs = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:data error:nil];
    for (NSString *str in unarchiverStrs) {
        NSLog(@"%@", str);
    }
    

    5. 归档宏SERIALIZER_CODER_DECODER

    • Runtime+CoderDeCoder.h
    #import <objc/runtime.h>
    
    //https://blog.csdn.net/longlongValue/article/details/81060583
    
    #define SERIALIZER_CODER_DECODER     \
    \
    - (id)initWithCoder:(NSCoder *)coder    \
    {   \
        Class cls = [self class];   \
        while (cls != [NSObject class]) {   \
            /*判断是自身类还是父类*/    \
            BOOL bIsSelfClass = (cls == [self class]);  \
            unsigned int iVarCount = 0; \
            unsigned int propVarCount = 0;  \
            unsigned int sharedVarCount = 0;    \
            Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表,含属性以及私有变量*/   \
            objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/   \
            sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
    \
            for (int i = 0; i < sharedVarCount; i++) {  \
                const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
                NSString *key = [NSString stringWithUTF8String:varName];   \
                id varValue = [coder decodeObjectForKey:key];   \
                NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
                if (varValue && [filters containsObject:key] == NO) { \
                    [self setValue:varValue forKey:key];    \
                }   \
            }   \
            free(ivarList); \
            free(propList); \
            cls = class_getSuperclass(cls); \
        }   \
        return self;    \
    }   \
    \
    - (void)encodeWithCoder:(NSCoder *)coder    \
    {   \
        Class cls = [self class];   \
        while (cls != [NSObject class]) {   \
            /*判断是自身类还是父类*/    \
            BOOL bIsSelfClass = (cls == [self class]);  \
            unsigned int iVarCount = 0; \
            unsigned int propVarCount = 0;  \
            unsigned int sharedVarCount = 0;    \
            Ivar *ivarList = bIsSelfClass ? class_copyIvarList([cls class], &iVarCount) : NULL;/*变量列表,含属性以及私有变量*/   \
            objc_property_t *propList = bIsSelfClass ? NULL : class_copyPropertyList(cls, &propVarCount);/*属性列表*/ \
            sharedVarCount = bIsSelfClass ? iVarCount : propVarCount;   \
            \
            for (int i = 0; i < sharedVarCount; i++) {  \
                const char *varName = bIsSelfClass ? ivar_getName(*(ivarList + i)) : property_getName(*(propList + i)); \
                NSString *key = [NSString stringWithUTF8String:varName];    \
                /*valueForKey只能获取本类所有变量以及所有层级父类的属性,不包含任何父类的私有变量(会崩溃)*/  \
                id varValue = [self valueForKey:key];   \
                NSArray *filters = @[@"superclass", @"description", @"debugDescription", @"hash"]; \
                if (varValue && [filters containsObject:key] == NO) { \
                    [coder encodeObject:varValue forKey:key];   \
                }   \
            }   \
            free(ivarList); \
            free(propList); \
            cls = class_getSuperclass(cls); \
        }   \
    }\
    \
    + (BOOL)supportsSecureCoding {\
        return YES;\
    }
    

    6. 给NSObject分类添加归档方法

    • NSObject+Archiver.h
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface NSObject (Archiver)
    
    /**
     object: 自定义对象、自定义对象数组/字典、基本数据类型/数组/字典
     classTypes: 自定义对象1个 自定义对象数组/字典2个
     custom:是否自定义对象
     */
    - (id)extArchivierObjectClassType:(Class)classType customType:(BOOL)custom;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    • NSObject+Archiver.m
    #import "NSObject+Archiver.h"
    
    @implementation NSObject (Archiver)
    
    - (id)extArchivierObjectClassType:(Class)classType customType:(BOOL)custom {
        
        //1. 判断objcect的类型 数组/字典/非集合
        
        //1.1 数组
        if ([self isKindOfClass:[NSArray class]]) {
            
            NSArray *items = (NSArray *)self;
            
            //2. 判断是否是自定义对象
            if (custom) {
                
                //归档对象未遵守 NSSecureCoding 协议
                if (![items.firstObject conformsToProtocol:@protocol(NSSecureCoding)]) {
                    NSLog(@"-----自定义类 未遵守 NSSecureCoding 协议-----");
                    return nil;
                }
                
                NSData *data = [NSKeyedArchiver archivedDataWithRootObject:items requiringSecureCoding:NO error:nil];
                NSArray *unarchiver = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[classType, NSArray.class]] fromData:data error:nil];
                return unarchiver;
            } else {
                NSData *data = [NSKeyedArchiver archivedDataWithRootObject:items requiringSecureCoding:NO error:nil];
                NSArray *unarchiver = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:data error:nil];
                return unarchiver;
            }
        }
        //1.2 字典
        else if ([self isKindOfClass:[NSDictionary class]]) {
            
            NSDictionary *dic = (NSDictionary *)self;
            
            //2. 判断是否是自定义对象
            if (custom) {
                
                //归档对象未遵守 NSSecureCoding 协议
                if (![dic.allValues.firstObject conformsToProtocol:@protocol(NSSecureCoding)]) {
                    NSLog(@"-----自定义类 未遵守 NSSecureCoding 协议-----");
                    return nil;
                }
                
                NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dic requiringSecureCoding:NO error:nil];
                NSDictionary *unarchiver = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[classType, NSDictionary.class]] fromData:data error:nil];
                return unarchiver;
            } else {
                NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dic requiringSecureCoding:NO error:nil];
                NSDictionary *unarchiver = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSDictionary class] fromData:data error:nil];
                return unarchiver;
            }
        }
        
        //1.3 非集合的
        if (custom) {
            //归档对象未遵守 NSSecureCoding 协议
            if (![self conformsToProtocol:@protocol(NSSecureCoding)]) {
                NSLog(@"-----自定义类 未遵守 NSSecureCoding 协议-----");
                return nil;
            }
        }
            
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self requiringSecureCoding:NO error:nil];
        return [NSKeyedUnarchiver unarchivedObjectOfClass:classType fromData:data error:nil];
    }
    
    @end
    
    • 测试
    - (void)extStringDemo {
            //字符串数组归档
        NSMutableArray *strs = [NSMutableArray arrayWithArray:@[@"book1", @"book2"]];
        id archive = [strs extArchivierObjectClassType:NSString.class customType:NO];
    //    for (NSString *ss in unarchiverss) {
    //        NSLog(@"ss---%@", ss);
    //    }
        
        strs[0] = @"new book1";
    }
    
    - (void)extBookDemo {
        Book *book1 = [Book new];
        book1.bookName = @"book1";
        
        id archive = [book1 extArchivierObjectClassType:[Book class] customType:YES];
    
        //修改book
        book1.bookName = @"new bookName 1";
        NSLog(@"old:%@ - new:%@", book1.bookName, archive);
    }
    
    - (void)extArchiverArrayDemo {
        Book *book1 = [Book new];
        book1.bookName = @"book1";
    
        Book *book2 = [Book new];
        book2.bookName = @"book2";
    
        NSArray *books = @[book1, book2];
        NSArray *unarchivers = [books extArchivierObjectClassType:[Book class] customType:YES];
    
        //修改book2
        Book *nb = books.lastObject;
        nb.bookName = @"new bookName 2";
    
        //打印原来的books
        for (Book *book in books) {
            NSLog(@"1---%@", book.bookName);
        }
    
        //打印解档的books
        for (Book *book in unarchivers) {
            NSLog(@"2---%@", book.bookName);
        }
    }
    
    - (void)extArchiverDictionaryDemo {
        Book *book1 = [Book new];
        book1.bookName = @"book1";
    
        Book *book2 = [Book new];
        book2.bookName = @"book2";
    
        NSDictionary *dic = @{@"a": book1, @"b": book2};
        for (Book *book in dic.allValues) {
            NSLog(@"1---%@", book.bookName);
        }
        NSDictionary *unarchivers = [dic extArchivierObjectClassType:[Book class] customType:YES];
    
        //修改book2
        Book *nb = dic.allValues.lastObject;
        nb.bookName = @"new bookName";
        
        //打印原来的books
        for (Book *book in dic.allValues) {
            NSLog(@"2---%@", book.bookName);
        }
    
        //打印解档的books
        for (Book *book in unarchivers.allValues) {
            NSLog(@"2---%@", book.bookName);
        }
    }
    

    7. 制作静态库.a

    • 创建静态库,名称:StaticLibrary
    image.png
    • 将归档的分类文件拖进来(这里将生成的StaticLibrary.hStaticLibrary.m删除了)
      build phasescopy files添加.h
    image.png
    • 切换debugrelease模式
    image.png
    • 编译.a
    image.png

    得到不同架构的.a文件

    image.png
    • 合并2个.a得到ArchiveFramework.a

    lipo -create 静态库1的路径 静态库2的路径 -output 要生成的静态库路径+静态库名称

    lipo -create ../Release-iphoneos/libStaticLibrary.a libStaticLibrary.a -output ArchiveFramework.a
    
    image.png
    • .h.a拖入项目就可以调用了
    image.png image.png

    相关文章

      网友评论

          本文标题:归档archive

          本文链接:https://www.haomeiwen.com/subject/vtilqktx.html