Skip to content

Commit

Permalink
Add more tests for
Browse files Browse the repository at this point in the history
  - `String to Data` case
  - `AttributedString to String` case
Remove unnecessary ivar of cache class.
Boost large properties with small amount dictionary. #197
  • Loading branch information
wolfcon committed Dec 23, 2021
1 parent 2dabd35 commit 422db23
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 60 deletions.
12 changes: 12 additions & 0 deletions MJExtension.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
0130EE80233C56D8008D2386 /* MJFrenchUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 0130EE7F233C56D8008D2386 /* MJFrenchUser.m */; };
0179886C24EFA460007F7FBC /* MJTester.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0179886B24EFA460007F7FBC /* MJTester.swift */; };
0179887024EFA58B007F7FBC /* SwiftModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */; };
01BC91E2277418DF004E5265 /* ValueTransformingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */; };
01BC91E427741956004E5265 /* MJCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E327741956004E5265 /* MJCredential.swift */; };
01BC91E627741D8C004E5265 /* MJArticle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E527741D8C004E5265 /* MJArticle.swift */; };
01D3949B26FACE7D00457B88 /* MJCoreDataTestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 0107507626E88DD400AAEA10 /* MJCoreDataTestModel.xcdatamodeld */; };
01F28187248F64ED008775BA /* MJCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F28186248F64ED008775BA /* MJCat.m */; };
01F5515E2757144500518218 /* MJEClass.h in Headers */ = {isa = PBXBuildFile; fileRef = 01F5515C2757144500518218 /* MJEClass.h */; settings = {ATTRIBUTES = (Private, ); }; };
Expand Down Expand Up @@ -91,6 +94,9 @@
0179886A24EFA460007F7FBC /* MJExtensionTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MJExtensionTests-Bridging-Header.h"; sourceTree = "<group>"; };
0179886B24EFA460007F7FBC /* MJTester.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJTester.swift; sourceTree = "<group>"; };
0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftModelTests.swift; sourceTree = "<group>"; };
01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueTransformingTest.swift; sourceTree = "<group>"; };
01BC91E327741956004E5265 /* MJCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJCredential.swift; sourceTree = "<group>"; };
01BC91E527741D8C004E5265 /* MJArticle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJArticle.swift; sourceTree = "<group>"; };
01F28185248F64ED008775BA /* MJCat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJCat.h; sourceTree = "<group>"; };
01F28186248F64ED008775BA /* MJCat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MJCat.m; sourceTree = "<group>"; };
01F5515C2757144500518218 /* MJEClass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJEClass.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -202,6 +208,8 @@
isa = PBXGroup;
children = (
0179886B24EFA460007F7FBC /* MJTester.swift */,
01BC91E327741956004E5265 /* MJCredential.swift */,
01BC91E527741D8C004E5265 /* MJArticle.swift */,
);
path = SwiftModel;
sourceTree = "<group>";
Expand Down Expand Up @@ -261,6 +269,7 @@
0107507526E88DA600AAEA10 /* CoreDataModel */,
2D2DBA5F2317DBDF005A689E /* Model */,
2D2DBA572317DBB9005A689E /* MJExtensionTests.m */,
01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */,
010DF01D2761D90A0007EEF0 /* SpecialPropertyTypeTests.swift */,
0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */,
01052EAC25F872D00049EC6F /* MultiThreadTests.swift */,
Expand Down Expand Up @@ -522,6 +531,7 @@
buildActionMask = 2147483647;
files = (
2D2DBA812317DBE0005A689E /* MJStatusResult.m in Sources */,
01BC91E627741D8C004E5265 /* MJArticle.swift in Sources */,
2D2DBA7C2317DBE0005A689E /* MJStudent.m in Sources */,
2D2DBA822317DBE0005A689E /* MJStatus.m in Sources */,
2D2DBA832317DBE0005A689E /* MJAd.m in Sources */,
Expand All @@ -534,6 +544,7 @@
01F551642758C74F00518218 /* NSObject+MJExtensionExample.m in Sources */,
2D2DBA852317DBE0005A689E /* MJPerson.m in Sources */,
0107507C26E88EAC00AAEA10 /* MJCoreDataTester+CoreDataProperties.swift in Sources */,
01BC91E2277418DF004E5265 /* ValueTransformingTest.swift in Sources */,
2D2DBA7B2317DBE0005A689E /* MJBox.m in Sources */,
2D2DBA582317DBB9005A689E /* MJExtensionTests.m in Sources */,
010DF01E2761D90A0007EEF0 /* SpecialPropertyTypeTests.swift in Sources */,
Expand All @@ -544,6 +555,7 @@
0107507826E88DD400AAEA10 /* MJCoreDataTestModel.xcdatamodeld in Sources */,
2D2DBA7A2317DBE0005A689E /* MJDog.m in Sources */,
01052EAD25F872D00049EC6F /* MultiThreadTests.swift in Sources */,
01BC91E427741956004E5265 /* MJCredential.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
5 changes: 4 additions & 1 deletion MJExtension/MJEClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ NS_ASSUME_NONNULL_BEGIN

NSArray<MJProperty *> * _Nullable _allProperties2JSON;
NSDictionary <NSString *, MJProperty *> *_mapper;
NSArray<MJProperty *> *_multiKeysProperties;

BOOL _hasOld2NewModifier;
BOOL _hasLocaleModifier;
BOOL _hasDictionary2ObjectModifier;
BOOL _hasObject2DictionaryModifier;
BOOL _hasClassModifier;

BOOL _needsUpdate;
/// = _allProperties.count
NSInteger _propertiesCount;
NSLocale * _Nullable _locale;
}

- (void)setNeedsUpdate;
Expand Down
14 changes: 11 additions & 3 deletions MJExtension/MJEClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ - (instancetype)initWithClass:(Class)cls {
hasKeyReplacementModifier:hasKeyReplacementModifier
inClass:cls];

_hasLocaleModifier = [cls respondsToSelector:@selector(mj_locale)];
if ([cls respondsToSelector:@selector(mj_locale)]) {
_locale = [(Class<MJEConfiguration>)cls mj_locale];
}
_hasOld2NewModifier = [cls instancesRespondToSelector:@selector(mj_newValueFromOldValue:property:)];
// TODO: 4.0.0 new feature
// _hasClassModifier = [
Expand Down Expand Up @@ -156,6 +158,7 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList
NSMutableArray<MJProperty *> *allProperties = [NSMutableArray array];
NSMutableArray<MJProperty *> *codingProperties = [NSMutableArray array];
NSMutableDictionary *mapper = [NSMutableDictionary new];
NSMutableArray<MJProperty *> *multiKeysProperties = [NSMutableArray array];
// TODO: 4.0.0 new feature
// NSMutableArray<MJProperty *> *allProperties2JSON = [NSMutableArray array];
[cls mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
Expand Down Expand Up @@ -201,8 +204,10 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList

// handle keypath / keypath array / keypath array(with subkey)
[property handleOriginKey:key];
// The property matched with a singular key is only condition that should be considered.
if (!property->_isMultiMapping) {
// The property matched with a singular key is the only condition for dictionary enumeration.
if (property->_isMultiMapping) {
[multiKeysProperties addObject:property];
} else {
property->_nextSame = mapper[property->_mappedKey] ?: nil;
mapper[property->_mappedKey] = property;
}
Expand All @@ -224,6 +229,9 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList
_allProperties = allProperties.copy;
_allCodingProperties = codingProperties.copy;
_mapper = mapper.copy;
_multiKeysProperties = multiKeysProperties.copy;

_propertiesCount = _allProperties.count;
}

- (void)setNeedsUpdate {
Expand Down
2 changes: 2 additions & 0 deletions MJExtension/MJProperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ typedef NS_ENUM(NSUInteger, MJEBasicType) {
MJEBasicTypeMutableDictionary,
MJEBasicTypeMutableData,
MJEBasicTypeDecimalNumber,
MJEBasicTypeMutableAttributedString,

MJEBasicTypeString,
MJEBasicTypeSet,
MJEBasicTypeArray,
MJEBasicTypeDictionary,
MJEBasicTypeData,
MJEBasicTypeNumber,
MJEBasicTypeAttributedString,

MJEBasicTypeValue,
MJEBasicTypeDate,
Expand Down
2 changes: 2 additions & 0 deletions MJExtension/MJProperty.m
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,15 @@ always_inline MJEBasicType MJEGetBasicObjectType(Class cls) {
if ([cls isSubclassOfClass:NSMutableDictionary.class]) return MJEBasicTypeMutableDictionary;
if ([cls isSubclassOfClass:NSMutableData.class]) return MJEBasicTypeMutableData;
if ([cls isSubclassOfClass:NSDecimalNumber.class]) return MJEBasicTypeDecimalNumber;
if ([cls isSubclassOfClass:NSMutableAttributedString.class]) return MJEBasicTypeMutableAttributedString;

if ([cls isSubclassOfClass:NSString.class]) return MJEBasicTypeString;
if ([cls isSubclassOfClass:NSSet.class]) return MJEBasicTypeSet;
if ([cls isSubclassOfClass:NSArray.class]) return MJEBasicTypeArray;
if ([cls isSubclassOfClass:NSDictionary.class]) return MJEBasicTypeDictionary;
if ([cls isSubclassOfClass:NSData.class]) return MJEBasicTypeData;
if ([cls isSubclassOfClass:NSNumber.class]) return MJEBasicTypeNumber;
if ([cls isSubclassOfClass:NSAttributedString.class]) return MJEBasicTypeAttributedString;

if ([cls isSubclassOfClass:NSValue.class]) return MJEBasicTypeValue;
if ([cls isSubclassOfClass:NSDate.class]) return MJEBasicTypeDate;
Expand Down
91 changes: 58 additions & 33 deletions MJExtension/NSObject+MJKeyValue.m
Original file line number Diff line number Diff line change
Expand Up @@ -79,56 +79,73 @@ + (void)load

#pragma mark - --公共方法--
#pragma mark - 字典 -> 模型
- (instancetype)mj_setKeyValues:(id)keyValues
{
- (instancetype)mj_setKeyValues:(id)keyValues {
return [self mj_setKeyValues:keyValues context:nil];
}

/**
核心代码:
*/
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
- (instancetype)mj_setKeyValues:(id)keyValues
context:(NSManagedObjectContext *)context {
// 获得JSON对象
keyValues = [keyValues mj_JSONObject];
id object = [keyValues mj_JSONObject];

MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");
MJExtensionAssertError([object isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");

MJEClass *mjeClass = [MJEClass cachedClass:self.class];
NSArray<MJProperty *> *allProperties = mjeClass->_allProperties;
NSDictionary *dict = object;

NSLocale *numberLocale = nil;
if (mjeClass->_hasLocaleModifier) {
numberLocale = self.class.mj_locale;
if (mjeClass->_propertiesCount > dict.count) {
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
MJProperty *property = mjeClass->_mapper[key];
while (property) {
[self mj_setValue:value forProperty:property
context:context locale:mjeClass->_locale
classCache:mjeClass];
property = property->_nextSame;
}
}];
if (mjeClass->_multiKeysProperties.count) {
[self mj_enumerateProperties:mjeClass->_multiKeysProperties
withDictionary:dict classCache:mjeClass context:context];
}
} else {
[self mj_enumerateProperties:mjeClass->_allProperties
withDictionary:dict classCache:mjeClass
context:context];
}

[allProperties enumerateObjectsUsingBlock:^(MJProperty * _Nonnull property, NSUInteger idx, BOOL * _Nonnull stop) {

// 转换完毕
if (mjeClass->_hasDictionary2ObjectModifier) {
[self mj_didConvertToObjectWithKeyValues:keyValues];
}
return self;
}

- (void)mj_enumerateProperties:(NSArray<MJProperty *> *)properties
withDictionary:(NSDictionary *)dictionary
classCache:(MJEClass *)classCache
context:(NSManagedObjectContext *)context {
[properties enumerateObjectsUsingBlock:^(MJProperty * _Nonnull property, NSUInteger idx, BOOL * _Nonnull stop) {
@try {
// 1.取出属性值
id value;
if (!property->_isMultiMapping) {
value = keyValues[property->_mappedKey];
value = dictionary[property->_mappedKey];
} else {
for (NSArray *propertyKeys in property->_mappedMultiKeys) {
value = keyValues;
value = dictionary;
for (MJPropertyKey *propertyKey in propertyKeys) {
value = [propertyKey valueInObject:value];
}
if (value) break;
}
}

if (mjeClass->_hasOld2NewModifier
&& property->_hasValueModifier) {
id newValue = [self mj_newValueFromOldValue:value property:property];
if (newValue != value) { // 有过滤后的新值
[property setValue:newValue forObject:self];
return;
}
}

[self mj_setValue:value forProperty:property
inContext:context locale:numberLocale];
context:context locale:classCache->_locale
classCache:classCache];

} @catch (NSException *exception) {
MJExtensionBuildError([self class], exception.reason);
Expand All @@ -138,17 +155,21 @@ - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)
#endif
}
}];

// 转换完毕
if (mjeClass->_hasDictionary2ObjectModifier) {
[self mj_didConvertToObjectWithKeyValues:keyValues];
}
return self;
}

- (void)mj_setValue:(id)value forProperty:(MJProperty *)property
inContext:(NSManagedObjectContext *)context
locale:(NSLocale *)locale {
context:(NSManagedObjectContext *)context
locale:(NSLocale *)locale
classCache:(MJEClass *)classCache {
if (classCache->_hasOld2NewModifier
&& property->_hasValueModifier) {
id newValue = [self mj_newValueFromOldValue:value property:property];
if (newValue != value) { // 有过滤后的新值
[property setValue:newValue forObject:self];
return;
}
}

// 如果没有值,就直接返回
if (!value || value == NSNull.null) return;
// 2.复杂处理
Expand Down Expand Up @@ -198,6 +219,8 @@ - (void)mj_setValue:(id)value forProperty:(MJProperty *)property
long double num = [value mj_longDoubleValueWithLocale:locale];
mj_selfSend(property.setter, long double, num);
return;
} else if (property->_basicObjectType == MJEBasicTypeData || property->_basicObjectType == MJEBasicTypeMutableData) {
value = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
} else if (property.isNumber) {
NSString *oldValue = value;

Expand Down Expand Up @@ -377,8 +400,10 @@ - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArr
} else if ([value isKindOfClass:[NSArray class]]) {
// 3.处理数组里面有模型的情况
value = [NSObject mj_keyValuesArrayWithObjectArray:value];
} else if (propertyClass == [NSURL class]) {
} else if (property->_basicObjectType == MJEBasicTypeURL) {
value = [value absoluteString];
} else if (property->_basicObjectType == MJEBasicTypeAttributedString || property->_basicObjectType == MJEBasicTypeMutableAttributedString) {
value = [(NSAttributedString *)value string];
}

// 4.赋值
Expand Down
6 changes: 2 additions & 4 deletions MJExtensionTests/CoreDataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ class CoreDataTests: XCTestCase {
func json2CoreDataObject() {
context.performAndWait {
guard let tester = MJCoreDataTester.mj_object(withKeyValues: Values.testJSONObject, context: context) else {
XCTAssert(false, "conversion to core data object failed")
return
fatalError("conversion to core data object failed")
}

XCTAssert(tester.isJuan == Values.isJuan)
Expand All @@ -77,8 +76,7 @@ class CoreDataTests: XCTestCase {
coreDataObject.identifier = Values.identifier

guard let dict = coreDataObject.mj_keyValues() else {
XCTAssert(false, "conversion to keyValues failed")
return
fatalError("conversion to core data object failed")
}

XCTAssert(dict["isJuan"] as? Bool == Values.isJuan)
Expand Down
6 changes: 2 additions & 4 deletions MJExtensionTests/MultiThreadTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ class MultiThreadTests: XCTestCase {
sleep(1)
let testerDict = self.testerJSON(id)
guard let _ = MJTester.mj_object(withKeyValues: testerDict) else {
XCTAssert(false, "conversion failed")
return
fatalError("conversion failed")
}
print("tester: \(id)")
// XCTAssert(tester.isSpecialAgent)
Expand All @@ -59,8 +58,7 @@ class MultiThreadTests: XCTestCase {
sleep(1)
let catDict = self.catJSON(id)
guard let _ = MJCat.mj_object(withKeyValues: catDict) else {
XCTAssert(false, "convertion failed")
return
fatalError("conversion failed")
}
print("cat: \(id)")
// cat.nicknames?.forEach({ (nickname) in
Expand Down
14 changes: 14 additions & 0 deletions MJExtensionTests/SwiftModel/MJArticle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// MJArticle.swift
// MJExtensionTests
//
// Created by Frank on 2021/12/23.
// Copyright © 2021 MJ Lee. All rights reserved.
//

import Foundation

@objcMembers
class MJArticle: NSObject {
var attributedTitle: NSAttributedString?
}
13 changes: 13 additions & 0 deletions MJExtensionTests/SwiftModel/MJCredential.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// MJCredential.swift
// MJExtensionTests
//
// Created by Frank on 2021/12/23.
// Copyright © 2021 MJ Lee. All rights reserved.
//

import Foundation
@objcMembers
class MJCredential: NSObject {
var data: Data?
}
Loading

0 comments on commit 422db23

Please sign in to comment.