归档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)
}
自定义对象的归档,使用iOS11
的API
+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:
方法
+ (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
- 将归档的分类文件拖进来(这里将生成的
StaticLibrary.h
、StaticLibrary.m
删除了)
在build phases
的copy files
添加.h
- 切换
debug
、release
模式
- 编译
.a
得到不同架构的.a
文件
- 合并2个
.a
得到ArchiveFramework.a
lipo -create 静态库1的路径 静态库2的路径 -output 要生成的静态库路径+静态库名称
lipo -create ../Release-iphoneos/libStaticLibrary.a libStaticLibrary.a -output ArchiveFramework.a
image.png
- 将
.h
、.a
拖入项目就可以调用了