mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-26 07:57:41 +00:00
* Separate dataSource & UIKit index spaces Beef up our supplementary node support Make the API way better Go nuts Add a unit test for UICollectionView's handling of reloadData inside batch updates Wrap indexPathForNode: in a cache Convert index paths in delegate methods Go back on table view Put collection view back Switch up the API Move most ASCollectionView API to ASCollectionNode Move most table logic over to ASTableNode Do the things More conversion work Keep on keepin' on Get table view delegate API done More porting Simplify Clear the delegate More cleanup Move more stuff around Remove pointless file Re-add some API Put back more API Use the right flag * Some cleanup * Remove incorrect comment * Tweak the API * Put back a couple methods * update example projects (note: ASCollectionView deprecation warnings expected) * change reloadDataWithCompletion:nil --> reloadData * Clean up rebase * Make deprecated numberOfItemsInSection methods optional * Use the right flag * Address nits * update ASDKTube, ASDKgram & ASViewController examples
221 lines
9.2 KiB
Objective-C
221 lines
9.2 KiB
Objective-C
//
|
|
// ASDelegateProxy.m
|
|
// AsyncDisplayKit
|
|
//
|
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
//
|
|
|
|
#import "ASDelegateProxy.h"
|
|
#import "ASTableNode.h"
|
|
#import "ASCollectionNode.h"
|
|
#import "ASAssert.h"
|
|
|
|
@implementation ASTableViewProxy
|
|
|
|
- (BOOL)interceptsSelector:(SEL)selector
|
|
{
|
|
return (
|
|
// handled by ASTableView node<->cell machinery
|
|
selector == @selector(tableView:cellForRowAtIndexPath:) ||
|
|
selector == @selector(tableView:heightForRowAtIndexPath:) ||
|
|
|
|
// Selection, highlighting, menu
|
|
selector == @selector(tableView:willSelectRowAtIndexPath:) ||
|
|
selector == @selector(tableView:didSelectRowAtIndexPath:) ||
|
|
selector == @selector(tableView:willDeselectRowAtIndexPath:) ||
|
|
selector == @selector(tableView:didDeselectRowAtIndexPath:) ||
|
|
selector == @selector(tableView:shouldHighlightRowAtIndexPath:) ||
|
|
selector == @selector(tableView:didHighlightRowAtIndexPath:) ||
|
|
selector == @selector(tableView:didUnhighlightRowAtIndexPath:) ||
|
|
selector == @selector(tableView:shouldShowMenuForRowAtIndexPath:) ||
|
|
selector == @selector(tableView:canPerformAction:forRowAtIndexPath:withSender:) ||
|
|
selector == @selector(tableView:performAction:forRowAtIndexPath:withSender:) ||
|
|
|
|
// handled by ASRangeController
|
|
selector == @selector(numberOfSectionsInTableView:) ||
|
|
selector == @selector(tableView:numberOfRowsInSection:) ||
|
|
|
|
// reordering support
|
|
selector == @selector(tableView:canMoveRowAtIndexPath:) ||
|
|
selector == @selector(tableView:moveRowAtIndexPath:toIndexPath:) ||
|
|
|
|
// used for ASCellNode visibility
|
|
selector == @selector(scrollViewDidScroll:) ||
|
|
|
|
// used for ASCellNode user interaction
|
|
selector == @selector(scrollViewWillBeginDragging:) ||
|
|
selector == @selector(scrollViewDidEndDragging:willDecelerate:) ||
|
|
|
|
// used for ASRangeController visibility updates
|
|
selector == @selector(tableView:willDisplayCell:forRowAtIndexPath:) ||
|
|
selector == @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:) ||
|
|
|
|
// used for batch fetching API
|
|
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
|
);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation ASCollectionViewProxy
|
|
|
|
- (BOOL)interceptsSelector:(SEL)selector
|
|
{
|
|
return (
|
|
// handled by ASCollectionView node<->cell machinery
|
|
selector == @selector(collectionView:cellForItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:layout:sizeForItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:) ||
|
|
|
|
// Selection, highlighting, menu
|
|
selector == @selector(collectionView:shouldSelectItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:didSelectItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:shouldDeselectItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:didDeselectItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:shouldHighlightItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:didHighlightItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:didUnhighlightItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:shouldShowMenuForItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:canPerformAction:forItemAtIndexPath:withSender:) ||
|
|
selector == @selector(collectionView:performAction:forItemAtIndexPath:withSender:) ||
|
|
|
|
// Item counts
|
|
selector == @selector(numberOfSectionsInCollectionView:) ||
|
|
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
|
|
|
// Element appearance callbacks
|
|
selector == @selector(collectionView:willDisplayCell:forItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:willDisplaySupplementaryView:forElementKind:atIndexPath:) ||
|
|
selector == @selector(collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:) ||
|
|
|
|
// used for batch fetching API
|
|
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:) ||
|
|
|
|
// used for ASCellNode visibility
|
|
selector == @selector(scrollViewDidScroll:) ||
|
|
|
|
// used for ASCellNode user interaction
|
|
selector == @selector(scrollViewWillBeginDragging:) ||
|
|
selector == @selector(scrollViewDidEndDragging:willDecelerate:) ||
|
|
|
|
// intercepted due to not being supported by ASCollectionView (prevent bugs caused by usage)
|
|
selector == @selector(collectionView:canMoveItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:moveItemAtIndexPath:toIndexPath:)
|
|
);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation ASPagerNodeProxy
|
|
|
|
- (BOOL)interceptsSelector:(SEL)selector
|
|
{
|
|
return (
|
|
// handled by ASPagerDataSource node<->cell machinery
|
|
selector == @selector(collectionView:nodeForItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:nodeBlockForItemAtIndexPath:) ||
|
|
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
|
selector == @selector(collectionView:constrainedSizeForNodeAtIndexPath:)
|
|
);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation ASDelegateProxy {
|
|
id <ASDelegateProxyInterceptor> __weak _interceptor;
|
|
id <NSObject> __weak _target;
|
|
}
|
|
|
|
- (instancetype)initWithTarget:(id <NSObject>)target interceptor:(id <ASDelegateProxyInterceptor>)interceptor
|
|
{
|
|
// -[NSProxy init] is undefined
|
|
if (!self) {
|
|
return nil;
|
|
}
|
|
|
|
ASDisplayNodeAssert(interceptor, @"interceptor must not be nil");
|
|
|
|
_target = target ? : [NSNull null];
|
|
_interceptor = interceptor;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)conformsToProtocol:(Protocol *)aProtocol
|
|
{
|
|
if (_target) {
|
|
return [_target conformsToProtocol:aProtocol];
|
|
} else {
|
|
return [super conformsToProtocol:aProtocol];
|
|
}
|
|
}
|
|
|
|
- (BOOL)respondsToSelector:(SEL)aSelector
|
|
{
|
|
if ([self interceptsSelector:aSelector]) {
|
|
return [_interceptor respondsToSelector:aSelector];
|
|
} else {
|
|
// Also return NO if _target has become nil due to zeroing weak reference (or placeholder initialization).
|
|
return [_target respondsToSelector:aSelector];
|
|
}
|
|
}
|
|
|
|
- (id)forwardingTargetForSelector:(SEL)aSelector
|
|
{
|
|
if ([self interceptsSelector:aSelector]) {
|
|
return _interceptor;
|
|
} else {
|
|
if (_target) {
|
|
return [_target respondsToSelector:aSelector] ? _target : nil;
|
|
} else {
|
|
// The _interceptor needs to be nilled out in this scenario. For that a strong reference needs to be created
|
|
// to be able to nil out the _interceptor but still let it know that the proxy target has deallocated
|
|
// We have to hold a strong reference to the interceptor as we have to nil it out and call the proxyTargetHasDeallocated
|
|
// The reason that the interceptor needs to be nilled out is that there maybe a change of a infinite loop, for example
|
|
// if a method will be called in the proxyTargetHasDeallocated: that again would trigger a whole new forwarding cycle
|
|
id <ASDelegateProxyInterceptor> interceptor = _interceptor;
|
|
_interceptor = nil;
|
|
[interceptor proxyTargetHasDeallocated:self];
|
|
|
|
return nil;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
|
{
|
|
// Check for a compiled definition for the selector
|
|
NSMethodSignature *methodSignature = nil;
|
|
if ([self interceptsSelector:aSelector]) {
|
|
methodSignature = [[_interceptor class] instanceMethodSignatureForSelector:aSelector];
|
|
} else {
|
|
methodSignature = [[_target class] instanceMethodSignatureForSelector:aSelector];
|
|
}
|
|
|
|
// Unfortunately, in order to get this object to work properly, the use of a method which creates an NSMethodSignature
|
|
// from a C string. -methodSignatureForSelector is called when a compiled definition for the selector cannot be found.
|
|
// This is the place where we have to create our own dud NSMethodSignature. This is necessary because if this method
|
|
// returns nil, a selector not found exception is raised. The string argument to -signatureWithObjCTypes: outlines
|
|
// the return type and arguments to the message. To return a dud NSMethodSignature, pretty much any signature will
|
|
// suffice. Since the -forwardInvocation call will do nothing if the delegate does not respond to the selector,
|
|
// the dud NSMethodSignature simply gets us around the exception.
|
|
return methodSignature ?: [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
|
|
}
|
|
|
|
- (void)forwardInvocation:(NSInvocation *)invocation
|
|
{
|
|
// If we are down here this means _interceptor and _target where nil. Just don't do anything to prevent a crash
|
|
}
|
|
|
|
- (BOOL)interceptsSelector:(SEL)selector
|
|
{
|
|
ASDisplayNodeAssert(NO, @"This method must be overridden by subclasses.");
|
|
return NO;
|
|
}
|
|
|
|
@end
|