Skip to content

Commit

Permalink
Add NSSecureCoding support for quick implementation macro `MJSecureCo…
Browse files Browse the repository at this point in the history
…dingImplementation(class, isSupport)`. (#821)
  • Loading branch information
wolfcon authored Sep 13, 2021
1 parent 24087db commit e31c9a6
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 20 deletions.
15 changes: 13 additions & 2 deletions MJExtension/NSObject+MJCoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ return self; \
- (void)encodeWithCoder:(NSCoder *)encoder \
{ \
[self mj_encode:encoder]; \
}
}\

#define MJExtensionCodingImplementation MJCodingImplementation

#define MJSecureCodingImplementation(CLASS, FLAG) \
@interface CLASS (MJSecureCoding) <NSSecureCoding> \
@end \
@implementation CLASS (MJSecureCoding) \
MJCodingImplementation \
+ (BOOL)supportsSecureCoding { \
return FLAG; \
} \
@end \

#define MJExtensionCodingImplementation MJCodingImplementation
3 changes: 2 additions & 1 deletion MJExtension/NSObject+MJCoding.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ - (void)mj_decode:(NSCoder *)decoder
if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
if ([ignoredCodingPropertyNames containsObject:property.name]) return;

id value = [decoder decodeObjectForKey:property.name];
// fixed `-[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber'(This will be disallowed in the future.)` warning.
id value = [decoder decodeObjectOfClasses:[NSSet setWithObjects:NSNumber.class, property.type.typeClass, nil] forKey:property.name];
if (value == nil) { // 兼容以前的MJExtension版本
value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
}
Expand Down
14 changes: 11 additions & 3 deletions MJExtensionTests/MJExtensionTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#import <CoreData/CoreData.h>
#import "MJFrenchUser.h"
#import "MJCat.h"
#import <MJExtensionTests-Swift.h>

@interface MJExtensionTests : XCTestCase

Expand Down Expand Up @@ -440,13 +441,20 @@ - (void)testCoding {
MJBag *bag = [[MJBag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;
bag.isBig = YES;
bag.weight = 200;

NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bag.data"];
// 归档
[NSKeyedArchiver archiveRootObject:bag toFile:file];

NSError *error = nil;
// 归档
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:bag requiringSecureCoding:YES error:&error];
[data writeToFile:file atomically:true];

// 解档
MJBag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
NSData *readData = [NSFileManager.defaultManager contentsAtPath:file];
error = nil;
MJBag *decodedBag = [NSKeyedUnarchiver unarchivedObjectOfClass:MJBag.class fromData:readData error:&error];
MJExtensionLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
}

Expand Down
2 changes: 2 additions & 0 deletions MJExtensionTests/Model/MJBag.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@
@interface MJBag : NSObject
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) double price;
@property (nonatomic) BOOL isBig;
@property (nonatomic) NSInteger weight;
@end
5 changes: 3 additions & 2 deletions MJExtensionTests/Model/MJBag.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

@import MJExtension;

// NSSecureCoding实现
MJSecureCodingImplementation(MJBag, YES)

@implementation MJBag
// NSCoding实现
MJExtensionCodingImplementation

//+ (NSArray *)mj_ignoredCodingPropertyNames
//{
Expand Down
66 changes: 54 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ MJExtension
#### ‼️ `@objc` or `objcMembers` attributes should be added to class or property for declaration of Objc accessibility [在 Swift4 之后, 请在属性前加 `@objc` 修饰或在类前增加 `objcMembers`. 以保证 Swift 的属性能够暴露给 Objc 使用. ]‼️
#### ‼️ Use `NSNumber` instead of `Bool`, which is not bridged to `BOOL`. [请勿使用 `Bool` 类型, 因为在 Swift 中并没有桥接该类型, 不能显式的对应 `BOOL`, 请使用 `NSNumber` 替代] ‼️



## Contents

* [Getting Started 【开始使用】](#Getting_Started)
Expand All @@ -47,6 +45,7 @@ MJExtension
* [Model array -> JSON array](#Model_array_JSON_array)
* [Core Data](#Core_Data)
* [Coding](#Coding)
* [Secure Coding](#SecureCoding)
* [Camel -> underline](#Camel_underline)
* [NSString -> NSDate, nil -> @""](#NSString_NSDate)
* [NSDate -> NSString](#NSDate_NSString)
Expand All @@ -65,7 +64,7 @@ MJExtension
* `JSONString` --> `Model Array``Core Data Model Array`
* `Model Array``Core Data Model Array` --> `JSON Array`
* Coding all properties of a model with only one line of code.
* 只需要一行代码,就能实现模型的所有属性进行Coding(归档和解档)
* 只需要一行代码,就能实现模型的所有属性进行Coding / SecureCoding(归档和解档)

## <a id="Installation"></a> Installation【安装】

Expand Down Expand Up @@ -467,40 +466,83 @@ User *user = [User mj_objectWithKeyValues:dict context:context];
[context save:nil];
```

### <a id="Coding"></a> Coding
### <a id="Coding"></a> Coding (Archive & Unarchive methods are deprecated in iOS 12)

```objc
#import "MJExtension.h"

@implementation Bag
@implementation MJBag
// NSCoding Implementation
MJExtensionCodingImplementation
MJCodingImplementation
@end

/***********************************************/

// what properties not to be coded
[Bag mj_setupIgnoredCodingPropertyNames:^NSArray *{
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
return @[@"name"];
}];
// Equals: Bag.m implements +mj_ignoredCodingPropertyNames method.
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.

// Create model
Bag *bag = [[Bag alloc] init];
MJBag *bag = [[MJBag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;

NSString *file = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/bag.data"];
// Encoding
// Encoding by archiving
[NSKeyedArchiver archiveRootObject:bag toFile:file];

// Decoding
Bag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
// Decoding by unarchiving
MJBag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
NSLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
// name=(null), price=200.800000
```
### <a id="SecureCoding"></a> Secure Coding
Using `MJSecureCodingImplementation(class, isSupport)` macro.
```objc
@import MJExtension;
// NSSecureCoding Implementation
MJSecureCodingImplementation(MJBag, YES)
@implementation MJBag
@end
/***********************************************/
// what properties not to be coded
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
return @[@"name"];
}];
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.
// Create model
MJBag *bag = [[MJBag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;
bag.isBig = YES;
bag.weight = 200;
NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bag.data"];
NSError *error = nil;
// Encoding by archiving
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:bag requiringSecureCoding:YES error:&error];
[data writeToFile:file atomically:true];
// Decoding by unarchiving
NSData *readData = [NSFileManager.defaultManager contentsAtPath:file];
error = nil;
MJBag *decodedBag = [NSKeyedUnarchiver unarchivedObjectOfClass:MJBag.class fromData:readData error:&error];
MJExtensionLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
```

### <a id="Camel_underline"></a> Camel -> underline【统一转换属性名(比如驼峰转下划线)】

```objc
// Dog
#import "MJExtension.h"
Expand Down

0 comments on commit e31c9a6

Please sign in to comment.