归档archive

2020-07-02  本文已影响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协议

@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 { ... }
#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

#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分类添加归档方法

#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
#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

image.png image.png image.png image.png

得到不同架构的.a文件

image.png

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

lipo -create ../Release-iphoneos/libStaticLibrary.a libStaticLibrary.a -output ArchiveFramework.a
image.png image.png image.png
上一篇下一篇

猜你喜欢

热点阅读