Skip to content

Commit

Permalink
fix: Issue for primitive type returned from inovacation
Browse files Browse the repository at this point in the history
  • Loading branch information
SteinX committed Jan 25, 2020
1 parent 996b48c commit b02e930
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 7 deletions.
29 changes: 28 additions & 1 deletion Example/Tests/STXMessageProxyTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,37 @@ - (void)testOnBroadcastingSubscribersNotGetRetained {
[self.proxy addBroadcastSubscriber:subscriber1];
[self.proxy addBroadcastSubscriber:subscriber2];

__auto_type expect = [self expectationWithDescription:@"Subscription dealloc test"];

subscriber1 = nil;
subscriber2 = nil;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssert(self.proxy.isAllSubscriberGone, @"Subscribers should not be retained");
[expect fulfill];
});

[self waitForExpectations:@[expect] timeout:1.0];
}

XCTAssert(self.proxy.isAllSubscriberGone, @"Subscribers should not be retained");
- (void)testOnPrimitiveReturnTypeFromProxyingMethod {
[self.proxy setProxyingSelector:@selector(call_delegationWithStructReturnValue)
withRunningMode:STXMessageProxyRunningModeBroadcasting];

__auto_type subscriber1 = [STXTestMainDelegateImpl new];
__auto_type subscriber2 = [STXTestMainDelegateInterceptor new];

[self.proxy addBroadcastSubscriber:subscriber1];
[self.proxy addBroadcastSubscriber:subscriber2];

__auto_type returnVal = [self.mainObj call_delegationWithStructReturnVal];

XCTAssert(CGRectEqualToRect(returnVal, CGRectMake(1, 1, 10, 10)),
@"Return value is supposed to be returned from the source, since no interception will happen in the broadcasting mode");
XCTAssert(CGRectEqualToRect(subscriber1.evaluationStructValue, CGRectMake(1, 1, 10, 10)),
@"Evaluation value is supposed to be CGRectMake(1, 1, 10, 10) for subscriber1, as it's be invoked from the broadcasting");
XCTAssert(CGRectEqualToRect(subscriber2.evaluationStructValue, CGRectNull),
@"Evaluation value is supposed to be CGRectNull for subscriber2, as it's be invoked from the broadcasting");
}

@end
4 changes: 3 additions & 1 deletion Example/Tests/Utility/STXProxyingTestMain.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
// Copyright © 2019 SteinX. All rights reserved.
//

#import <Foundation/Foundation.h>
@import UIKit;

NS_ASSUME_NONNULL_BEGIN

@protocol STXProxyingTestMainDelegate <NSObject>

- (void)call_delegationWithParam:(id)parameter;
- (NSInteger)call_delegationWithReturnValue;
- (CGRect)call_delegationWithStructReturnValue;

@end

Expand All @@ -23,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN

- (void)call_delegationWithParam:(id)parameter;
- (NSInteger)call_delegationWithReturnVal;
- (CGRect)call_delegationWithStructReturnVal;

@end

Expand Down
4 changes: 4 additions & 0 deletions Example/Tests/Utility/STXProxyingTestMain.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ - (NSInteger)call_delegationWithReturnVal {
return [self.delegate call_delegationWithReturnValue];
}

- (CGRect)call_delegationWithStructReturnVal {
return [self.delegate call_delegationWithStructReturnValue];
}

@end
1 change: 1 addition & 0 deletions Example/Tests/Utility/STXTestMainDelegateImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface STXTestMainDelegateImpl : NSObject <STXProxyingTestMainDelegate>

@property (nonatomic, readonly, assign) NSInteger evaluationValue;
@property (nonatomic, readonly, assign) CGRect evaluationStructValue;

@end

Expand Down
5 changes: 5 additions & 0 deletions Example/Tests/Utility/STXTestMainDelegateImpl.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ - (NSInteger)call_delegationWithReturnValue {
return 10;
}

- (CGRect)call_delegationWithStructReturnValue {
_evaluationStructValue = CGRectMake(1, 1, 10, 10);
return _evaluationStructValue;
}

@end
1 change: 1 addition & 0 deletions Example/Tests/Utility/STXTestMainDelegateInterceptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface STXTestMainDelegateInterceptor : NSObject <STXProxyingTestMainDelegate>

@property (nonatomic, readonly, assign) NSInteger evaluationValue;
@property (nonatomic, readonly, assign) CGRect evaluationStructValue;

@end

Expand Down
5 changes: 5 additions & 0 deletions Example/Tests/Utility/STXTestMainDelegateInterceptor.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ - (NSInteger)call_delegationWithReturnValue {
return 20;
}

- (CGRect)call_delegationWithStructReturnValue {
_evaluationStructValue = CGRectNull;
return _evaluationStructValue;
}

@end
2 changes: 1 addition & 1 deletion STXMessageProxy.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'STXMessageProxy'
s.version = '0.1.0'
s.version = '0.1.1'
s.summary = 'A proxy to control the distribution of the message delivery of the objc based on the message forwarding mechanism.'

# This description is used to generate tags and improve search results.
Expand Down
44 changes: 40 additions & 4 deletions STXMessageProxy/Classes/STXMessageProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
#import "STXMessageProxy.h"
#import "NSObject+DeallocNotifiy.h"

NS_INLINE BOOL CStringEquals(const char *str1, const char *str2) {
return strcmp(str1, str2) == 0;
}

NS_INLINE BOOL isObjectType(const char *typeEncoding) {
return CStringEquals(typeEncoding, "@") // object
|| CStringEquals(typeEncoding, "@?") // block
|| CStringEquals(typeEncoding, "#"); // metaclass
}

NS_INLINE BOOL isVoidReturn(const char *typeEncoding) {
return CStringEquals(typeEncoding, "v");
}

@interface STXMessageProxy () <STXDeallocNotifierDelegate>

@property (nonatomic, weak) id<NSObject> source;
Expand Down Expand Up @@ -98,9 +112,26 @@ - (void)broadcastWithInvocation:(NSInvocation *)invocation {
// In broadcasting mode, return value of the invocation should be the one returned from the source,
// and the source should be informed at first
void *returnVal = NULL;
BOOL needsFree = NO;

if ([self.source respondsToSelector:targetSEL]) {
[invocation invokeWithTarget:self.source];
[invocation getReturnValue:&returnVal];

__auto_type retType = invocation.methodSignature.methodReturnType;

if (!isVoidReturn(retType)) {
if (isObjectType(retType)) {
[invocation getReturnValue:returnVal];
} else {
NSUInteger retValueSize;
NSGetSizeAndAlignment(retType, &retValueSize, NULL);

returnVal = malloc(retValueSize);
[invocation getReturnValue:returnVal];

needsFree = YES;
}
}
}

__auto_type subscriberEnumerator = self.broadcastSubscribers.objectEnumerator;
Expand All @@ -114,13 +145,18 @@ - (void)broadcastWithInvocation:(NSInvocation *)invocation {
subscriber = [subscriberEnumerator nextObject];
}

if (returnVal) {
[invocation setReturnValue:&returnVal];
if (returnVal != NULL) {
[invocation setReturnValue:returnVal];

if (needsFree) {
free(returnVal);
}
}
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
__auto_type signature = [[self.source class] methodSignatureForSelector:sel] ?: [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
__auto_type sourceSignature = [NSStringFromSelector(sel) hasPrefix:@"+"] ? [[self.source class] methodSignatureForSelector:sel] : [(id)self.source methodSignatureForSelector:sel];
__auto_type signature = sourceSignature != nil ? sourceSignature : [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
__auto_type runningMode = [self runningModeForSelector:sel];

if (runningMode != STXMessageProxyRunningModeInterception) {
Expand Down

0 comments on commit b02e930

Please sign in to comment.