Skip to content

Commit

Permalink
Merge pull request #59 from marty-suzuki/improve-delegate-proxy
Browse files Browse the repository at this point in the history
Add denying forward message to specific object in DelegateProxyBase
  • Loading branch information
marty-suzuki authored Sep 13, 2021
2 parents 0d50c16 + 55003a9 commit 5dacb00
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 160 deletions.
4 changes: 3 additions & 1 deletion ReverseExtension/DelegateProxyBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
//

#import <Foundation/Foundation.h>
#import "DenyDelegateMethod.h"

@interface DelegateProxyBase : NSObject
- (nonnull instancetype)initWithDelegates:(NSArray<id> * __nonnull)delegates NS_REFINED_FOR_SWIFT;
- (nonnull instancetype)initWithDelegates: (NSArray<id> * __nonnull)delegates
denyList: (NSArray<DenyDelegateMethod *> * __nonnull)denyList NS_REFINED_FOR_SWIFT;
@end
30 changes: 29 additions & 1 deletion ReverseExtension/DelegateProxyBase.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@

@interface DelegateProxyBase ()
@property (nonnull, nonatomic, strong) NSHashTable<NSObject *> *delegates;
@property (nonnull, nonatomic, strong) NSMapTable<NSString *, id> *denyDictionary;
@end

@implementation DelegateProxyBase

- (instancetype)initWithDelegates:(NSArray<id> *)delegates {
- (instancetype)initWithDelegates: (NSArray<id> *)delegates
denyList: (NSArray<DenyDelegateMethod *> *)denyList {
self = [super init];
if (self) {
NSMapTable<NSString *, id> *denyDictionary = [NSMapTable strongToWeakObjectsMapTable];
for (DenyDelegateMethod *denyDelegateMethod in denyList) {
NSString *key = NSStringFromSelector(denyDelegateMethod.selector);
[denyDictionary setObject:denyDelegateMethod.delegate forKey:key];
}
self.denyDictionary = denyDictionary;
self.delegates = [NSHashTable weakObjectsHashTable];
for (id delegate in delegates) {
if (![delegate isKindOfClass:[NSObject class]]) { continue; }
Expand All @@ -26,12 +34,25 @@ - (instancetype)initWithDelegates:(NSArray<id> *)delegates {
return self;
}

- (id)denyDelegateForSelector:(SEL)aSelector {
return [self.denyDictionary objectForKey:NSStringFromSelector(aSelector)];
}

- (BOOL)isDenyDelegateForSelector:(SEL)aSelector delegate:(id)delegate {
id denyDelegate = [self denyDelegateForSelector:aSelector];
return denyDelegate != nil && [delegate isEqual: denyDelegate];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
for (NSObject *delegate in self.delegates) {
if ([delegate isKindOfClass:[NSNull class]]) {
continue;
}

if ([delegate respondsToSelector:aSelector]) {
if ([self isDenyDelegateForSelector:aSelector delegate:delegate]) {
continue;
}
return YES;
}
}
Expand All @@ -43,7 +64,11 @@ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([delegate isKindOfClass:[NSNull class]]) {
continue;
}

if ([delegate respondsToSelector:aSelector]) {
if ([self isDenyDelegateForSelector:aSelector delegate:delegate]) {
continue;
}
return [delegate methodSignatureForSelector:aSelector];
}
}
Expand All @@ -56,6 +81,9 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation {
continue;
}
if ([delegate respondsToSelector:anInvocation.selector]) {
if ([self isDenyDelegateForSelector:anInvocation.selector delegate:delegate]) {
continue;
}
[anInvocation invokeWithTarget:delegate];
}
}
Expand Down
17 changes: 17 additions & 0 deletions ReverseExtension/DenyDelegateMethod.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// DenyDelegateMethod.h
// ReverseExtension
//
// Created by marty-suzuki on 2021/09/14.
//

#import <Foundation/Foundation.h>

@interface DenyDelegateMethod : NSObject

@property (readonly, nullable, nonatomic, weak) id delegate;
@property (readonly, nonnull, nonatomic, assign) SEL selector;

- (nonnull instancetype)initWithDelegate: (id __nonnull)delegate
selector: (SEL __nonnull)selector;
@end
27 changes: 27 additions & 0 deletions ReverseExtension/DenyDelegateMethod.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// DenyDelegateMethod.m
// ReverseExtension
//
// Created by marty-suzuki on 2021/09/14.
//

#import "DenyDelegateMethod.h"

@interface DenyDelegateMethod ()
@property (readwrite, nullable, nonatomic, weak) id delegate;
@property (readwrite, nonnull, nonatomic, assign) SEL selector;
@end

@implementation DenyDelegateMethod

- (instancetype)initWithDelegate: (id)delegate
selector: (SEL)selector {
self = [super init];
if (self) {
self.delegate = delegate;
self.selector = selector;
}
return self;
}

@end
36 changes: 34 additions & 2 deletions ReverseExtension/ReverseExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,32 @@ extension UITableView {
delegateProxy = nil
return
}
delegateProxy = UITableViewDelegateProxy(delegates: [delegate, self])

delegateProxy = UITableViewDelegateProxy(
delegates: [delegate, self],
denyList: denied(delegate) {
let newerDenyList: [Selector]
if #available(iOS 11, *) {
newerDenyList = [
#selector($0.tableView(_:trailingSwipeActionsConfigurationForRowAt:)),
#selector($0.tableView(_:leadingSwipeActionsConfigurationForRowAt:))
]
} else {
newerDenyList = []
}
return [
#selector($0.tableView(_:willDisplay:forRowAt:)),
#selector($0.tableView(_:willDisplayHeaderView:forSection:)),
#selector($0.tableView(_:willDisplayFooterView:forSection:)),
#selector($0.tableView(_:heightForHeaderInSection:)),
#selector($0.tableView(_:estimatedHeightForFooterInSection:)),
#selector($0.tableView(_:editingStyleForRowAt:)),
#selector($0.tableView(_:viewForHeaderInSection:)),
#selector($0.tableView(_:viewForFooterInSection:)),
#selector($0.tableView(_:didSelectRowAt:))
] + newerDenyList
}
)
}
}
public weak var dataSource: UITableViewDataSource? {
Expand Down Expand Up @@ -148,7 +173,14 @@ extension UITableView {
deinit {
pthread_mutex_destroy(&mutex)
}


private func denied<T: NSObjectProtocol>(
_ delegate: T,
selector: (T) -> [Selector]
) -> [DenyDelegateMethod] {
selector(delegate).map { DenyDelegateMethod(delegate: delegate, selector: $0) }
}

// MARK: - Initializer
fileprivate init(_ base: UITableView) {
self.base = base
Expand Down
7 changes: 5 additions & 2 deletions ReverseExtension/UITableViewDelegateProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
import UIKit

final class UITableViewDelegateProxy: DelegateProxyBase, UITableViewDelegate {
convenience init(delegates: [UITableViewDelegate]) {
self.init(__delegates: delegates)
convenience init(
delegates: [UITableViewDelegate],
denyList: [DenyDelegateMethod]
) {
self.init(__delegates: delegates, denyList: denyList)
}
}
4 changes: 2 additions & 2 deletions ReverseExtensionSample/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- ReverseExtension (0.5.0)
- ReverseExtension (0.6.0)
- TouchVisualizer (4.0.0)

DEPENDENCIES:
Expand All @@ -15,7 +15,7 @@ EXTERNAL SOURCES:
:path: "../"

SPEC CHECKSUMS:
ReverseExtension: e658309467ab80870648e32069d14b2ff4a09863
ReverseExtension: 5c7ca8c165f47e9bde8e26084d5e7bf21ad4f5a6
TouchVisualizer: d342dc3a567b6dd289bc31b7ce8681302a93dfee

PODFILE CHECKSUM: b8298876d13500af76d270fcdd0c8fad6d80316c
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ReverseExtensionSample/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5dacb00

Please sign in to comment.