Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: thread safe #312

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Framework/YYModel.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
0D84B87223D890F7005CC9E7 /* YYTestThreadSafe.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D84B87123D890F7005CC9E7 /* YYTestThreadSafe.m */; };
D927FA881F36EB6C007B972E /* YYModel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D927FA7E1F36EB6C007B972E /* YYModel.framework */; };
D930C3B51F36EDC4005A2D00 /* NSObject+YYModel.h in Headers */ = {isa = PBXBuildFile; fileRef = D930C3B01F36EDC4005A2D00 /* NSObject+YYModel.h */; settings = {ATTRIBUTES = (Public, ); }; };
D930C3B61F36EDC4005A2D00 /* NSObject+YYModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D930C3B11F36EDC4005A2D00 /* NSObject+YYModel.m */; };
Expand Down Expand Up @@ -39,6 +40,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
0D84B87123D890F7005CC9E7 /* YYTestThreadSafe.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YYTestThreadSafe.m; sourceTree = "<group>"; };
D927FA7E1F36EB6C007B972E /* YYModel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYModel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D927FA821F36EB6C007B972E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Framework/Info.plist; sourceTree = "<group>"; };
D927FA871F36EB6C007B972E /* YYModelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YYModelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -116,6 +118,7 @@
D97394F71F36EE2D00FC2DEB /* YYModelTests */ = {
isa = PBXGroup;
children = (
0D84B87123D890F7005CC9E7 /* YYTestThreadSafe.m */,
D97394F91F36EE2D00FC2DEB /* YYTestAutoTypeConvert.m */,
D97394FA1F36EE2D00FC2DEB /* YYTestBlacklistWhitelist.m */,
D97394FB1F36EE2D00FC2DEB /* YYTestClassInfo.m */,
Expand Down Expand Up @@ -262,6 +265,7 @@
D930C3B71F36EDC4005A2D00 /* NSObject+YYModel.m in Sources */,
D973950E1F36EE2D00FC2DEB /* YYTestModelMapper.m in Sources */,
D97395101F36EE2D00FC2DEB /* YYTestNestModel.m in Sources */,
0D84B87223D890F7005CC9E7 /* YYTestThreadSafe.m in Sources */,
D973950D1F36EE2D00FC2DEB /* YYTestHelper.m in Sources */,
D973950A1F36EE2D00FC2DEB /* YYTestCustomClass.m in Sources */,
D97395081F36EE2D00FC2DEB /* YYTestClassInfo.m in Sources */,
Expand Down
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
7 changes: 6 additions & 1 deletion YYModel/NSObject+YYModel.m
Expand Up @@ -641,7 +641,12 @@ + (instancetype)metaWithClass:(Class)cls {
meta = [[_YYModelMeta alloc] initWithClass:cls];
if (meta) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
_YYModelMeta *rmeta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
if (!rmeta) {
CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
} else {
meta = rmeta;
}
dispatch_semaphore_signal(lock);
}
}
Expand Down
7 changes: 6 additions & 1 deletion YYModel/YYClassInfo.m
Expand Up @@ -347,7 +347,12 @@ + (instancetype)classInfoWithClass:(Class)cls {
info = [[YYClassInfo alloc] initWithClass:cls];
if (info) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
YYClassInfo *rinfo = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
if (!rinfo) {
CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
} else {
info = rinfo;
}
dispatch_semaphore_signal(lock);
}
}
Expand Down
109 changes: 109 additions & 0 deletions YYModelTests/YYTestThreadSafe.m
@@ -0,0 +1,109 @@
//
// YYTestThreadSafe.m
// YYModelTests
//
// Created by jufan wang on 2020/1/22.
// Copyright © 2020 ibireme. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "YYModel.h"
#import "YYTestHelper.h"


@interface YYTestThreadSafeModel : NSObject

@property bool boolValue;
@property BOOL BOOLValue;
@property char charValue;
@property unsigned char unsignedCharValue;
@property short shortValue;
@property unsigned short unsignedShortValue;
@property int intValue;
@property unsigned int unsignedIntValue;
@property long longValue;
@property unsigned long unsignedLongValue;
@property long long longLongValue;
@property unsigned long long unsignedLongLongValue;
@property float floatValue;
@property double doubleValue;
@property long double longDoubleValue;
@property (strong) Class classValue;
@property SEL selectorValue;
@property (copy) void (^blockValue)();
@property void *pointerValue;
@property CGRect structValue;
@property CGPoint pointValue;

@end


@implementation YYTestThreadSafeModel
+ (NSDictionary *)modelCustomPropertyMapper {
return @{ @"boolValue" : @"v",
@"BOOLValue" : @"v",
@"charValue" : @"v"
};
}


@end





@interface YYTestThreadSafe : XCTestCase

@end

@implementation YYTestThreadSafe

- (void)testThreadSafe {
NSString *json;
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

json = @"[{\"v\":1},{\"v\":2},{\"v\":3}]";
[queue setSuspended:YES];
for (int i = 0; i < 100; i++) {
[queue addOperationWithBlock:^{
NSArray *array = [NSArray yy_modelArrayWithClass:YYTestThreadSafeModel.class json:json];
XCTAssertTrue(array.count == 3);
XCTAssertTrue([array.firstObject isKindOfClass:[YYTestThreadSafeModel class]]);
}];

}
[queue setSuspended:NO];
sleep(200);
for (int i = 0; i < 100; i++) {
[queue addOperationWithBlock:^{
NSArray *array = [NSArray yy_modelArrayWithClass:YYTestThreadSafeModel.class json:json];
XCTAssertTrue(array.count == 3);
XCTAssertTrue([array.firstObject isKindOfClass:[YYTestThreadSafeModel class]]);
}];

}
sleep(200);
}

- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}

- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}

@end