mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-11 17:00:02 +00:00
Add UIDataSourceModelAssociation to ASTableView and ASCollectionView (#1354)
* Add UIDataSourceModelAssociation protocol conformance to ASTableView and ASCollectionView. * Implementing review feedback from @Adlai-Holler
This commit is contained in:
parent
9b80eabd8f
commit
a38b3f547e
@ -672,6 +672,29 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)collectionNode:(ASCollectionNode *)collectionNode moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
|
- (void)collectionNode:(ASCollectionNode *)collectionNode moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique identifier for an element in a collection. This helps state restoration persist the scroll position
|
||||||
|
* of a collection view even when the data in that table changes. See the documentation for UIDataSourceModelAssociation for more information.
|
||||||
|
*
|
||||||
|
* @param indexPath The index path of the requested node.
|
||||||
|
*
|
||||||
|
* @param collectionNode The sender.
|
||||||
|
*
|
||||||
|
* @return a unique identifier for the element at the given path. Return nil if the index path does not exist in the collection.
|
||||||
|
*/
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inNode:(ASCollectionNode *)collectionNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to -collectionView:cellForItemAtIndexPath:. See the documentation for UIDataSourceModelAssociation for more information.
|
||||||
|
*
|
||||||
|
* @param identifier The model identifier of the element, previously generated by a call to modelIdentifierForElementAtIndexPath
|
||||||
|
*
|
||||||
|
* @param collectionNode The sender.
|
||||||
|
*
|
||||||
|
* @return the index path to the current position of the matching element in the collection. Return nil if the element is not found.
|
||||||
|
*/
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inNode:(ASCollectionNode *)collectionNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to -collectionView:cellForItemAtIndexPath:.
|
* Similar to -collectionView:cellForItemAtIndexPath:.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -230,6 +230,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
|||||||
unsigned int interopAlwaysDequeue:1;
|
unsigned int interopAlwaysDequeue:1;
|
||||||
// Whether this interop data source implements viewForSupplementaryElementOfKind:
|
// Whether this interop data source implements viewForSupplementaryElementOfKind:
|
||||||
unsigned int interopViewForSupplementaryElement:1;
|
unsigned int interopViewForSupplementaryElement:1;
|
||||||
|
unsigned int modelIdentifierMethods:1; // if both modelIdentifierForElementAtIndexPath and indexPathForElementWithModelIdentifier are implemented
|
||||||
} _asyncDataSourceFlags;
|
} _asyncDataSourceFlags;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -486,6 +487,9 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
|||||||
_asyncDataSourceFlags.interopViewForSupplementaryElement = [interopDataSource respondsToSelector:@selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:)];
|
_asyncDataSourceFlags.interopViewForSupplementaryElement = [interopDataSource respondsToSelector:@selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_asyncDataSourceFlags.modelIdentifierMethods = [_asyncDataSource respondsToSelector:@selector(modelIdentifierForElementAtIndexPath:inNode:)] && [_asyncDataSource respondsToSelector:@selector(indexPathForElementWithModelIdentifier:inNode:)];
|
||||||
|
|
||||||
|
|
||||||
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection || _asyncDataSourceFlags.collectionViewNumberOfItemsInSection, @"Data source must implement collectionNode:numberOfItemsInSection:");
|
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNumberOfItemsInSection || _asyncDataSourceFlags.collectionViewNumberOfItemsInSection, @"Data source must implement collectionNode:numberOfItemsInSection:");
|
||||||
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNodeBlockForItem
|
ASDisplayNodeAssert(_asyncDataSourceFlags.collectionNodeNodeBlockForItem
|
||||||
|| _asyncDataSourceFlags.collectionNodeNodeForItem
|
|| _asyncDataSourceFlags.collectionNodeNodeForItem
|
||||||
@ -805,6 +809,29 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
|||||||
// Subclass hook
|
// Subclass hook
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view {
|
||||||
|
if (_asyncDataSourceFlags.modelIdentifierMethods) {
|
||||||
|
GET_COLLECTIONNODE_OR_RETURN(collectionNode, nil);
|
||||||
|
NSIndexPath *convertedPath = [self convertIndexPathToCollectionNode:indexPath];
|
||||||
|
if (convertedPath == nil) {
|
||||||
|
return nil;
|
||||||
|
} else {
|
||||||
|
return [_asyncDataSource modelIdentifierForElementAtIndexPath:convertedPath inNode:collectionNode];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
|
||||||
|
if (_asyncDataSourceFlags.modelIdentifierMethods) {
|
||||||
|
GET_COLLECTIONNODE_OR_RETURN(collectionNode, nil);
|
||||||
|
return [_asyncDataSource indexPathForElementWithModelIdentifier:identifier inNode:collectionNode];
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Internal
|
#pragma mark Internal
|
||||||
|
|
||||||
- (void)_configureCollectionViewLayout:(nonnull UICollectionViewLayout *)layout
|
- (void)_configureCollectionViewLayout:(nonnull UICollectionViewLayout *)layout
|
||||||
|
|||||||
@ -569,6 +569,29 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)tableViewUnlockDataSource:(ASTableView *)tableView ASDISPLAYNODE_DEPRECATED_MSG("Data source accesses are on the main thread. Method will not be called.");
|
- (void)tableViewUnlockDataSource:(ASTableView *)tableView ASDISPLAYNODE_DEPRECATED_MSG("Data source accesses are on the main thread. Method will not be called.");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique identifier for an element in a table. This helps state restoration persist the scroll position
|
||||||
|
* of a table view even when the data in that table changes. See the documentation for UIDataSourceModelAssociation for more information.
|
||||||
|
*
|
||||||
|
* @param indexPath The index path of the requested node.
|
||||||
|
*
|
||||||
|
* @param tableNode The sender.
|
||||||
|
*
|
||||||
|
* @return a unique identifier for the element at the given path. Return nil if the index path does not exist in the table.
|
||||||
|
*/
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inNode:(ASTableNode *)tableNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to -tableView:cellForRowAtIndexPath:. See the documentation for UIDataSourceModelAssociation for more information.
|
||||||
|
*
|
||||||
|
* @param identifier The model identifier of the element, previously generated by a call to modelIdentifierForElementAtIndexPath.
|
||||||
|
*
|
||||||
|
* @param tableNode The sender.
|
||||||
|
*
|
||||||
|
* @return the index path to the current position of the matching element in the table. Return nil if the element is not found.
|
||||||
|
*/
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inNode:(ASTableNode *)tableNode;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -271,6 +271,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
unsigned int tableViewMoveRow:1;
|
unsigned int tableViewMoveRow:1;
|
||||||
unsigned int tableNodeMoveRow:1;
|
unsigned int tableNodeMoveRow:1;
|
||||||
unsigned int sectionIndexMethods:1; // if both section index methods are implemented
|
unsigned int sectionIndexMethods:1; // if both section index methods are implemented
|
||||||
|
unsigned int modelIdentifierMethods:1; // if both modelIdentifierForElementAtIndexPath and indexPathForElementWithModelIdentifier are implemented
|
||||||
} _asyncDataSourceFlags;
|
} _asyncDataSourceFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,6 +428,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
_asyncDataSourceFlags.tableViewCanMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:canMoveRowAtIndexPath:)];
|
_asyncDataSourceFlags.tableViewCanMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:canMoveRowAtIndexPath:)];
|
||||||
_asyncDataSourceFlags.tableViewMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:moveRowAtIndexPath:toIndexPath:)];
|
_asyncDataSourceFlags.tableViewMoveRow = [_asyncDataSource respondsToSelector:@selector(tableView:moveRowAtIndexPath:toIndexPath:)];
|
||||||
_asyncDataSourceFlags.sectionIndexMethods = [_asyncDataSource respondsToSelector:@selector(sectionIndexTitlesForTableView:)] && [_asyncDataSource respondsToSelector:@selector(tableView:sectionForSectionIndexTitle:atIndex:)];
|
_asyncDataSourceFlags.sectionIndexMethods = [_asyncDataSource respondsToSelector:@selector(sectionIndexTitlesForTableView:)] && [_asyncDataSource respondsToSelector:@selector(tableView:sectionForSectionIndexTitle:atIndex:)];
|
||||||
|
_asyncDataSourceFlags.modelIdentifierMethods = [_asyncDataSource respondsToSelector:@selector(modelIdentifierForElementAtIndexPath:inNode:)] && [_asyncDataSource respondsToSelector:@selector(indexPathForElementWithModelIdentifier:inNode:)];
|
||||||
|
|
||||||
ASDisplayNodeAssert(_asyncDataSourceFlags.tableViewNodeBlockForRow
|
ASDisplayNodeAssert(_asyncDataSourceFlags.tableViewNodeBlockForRow
|
||||||
|| _asyncDataSourceFlags.tableViewNodeForRow
|
|| _asyncDataSourceFlags.tableViewNodeForRow
|
||||||
@ -961,6 +963,29 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
return [_dataController.visibleMap numberOfItemsInSection:section];
|
return [_dataController.visibleMap numberOfItemsInSection:section];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view {
|
||||||
|
if (_asyncDataSourceFlags.modelIdentifierMethods) {
|
||||||
|
GET_TABLENODE_OR_RETURN(tableNode, nil);
|
||||||
|
NSIndexPath *convertedPath = [self convertIndexPathToTableNode:indexPath];
|
||||||
|
if (convertedPath == nil) {
|
||||||
|
return nil;
|
||||||
|
} else {
|
||||||
|
return [_asyncDataSource modelIdentifierForElementAtIndexPath:convertedPath inNode:tableNode];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
|
||||||
|
if (_asyncDataSourceFlags.modelIdentifierMethods) {
|
||||||
|
GET_TABLENODE_OR_RETURN(tableNode, nil);
|
||||||
|
return [_asyncDataSource indexPathForElementWithModelIdentifier:identifier inNode:tableNode];
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
|
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (_asyncDataSourceFlags.tableViewCanMoveRow) {
|
if (_asyncDataSourceFlags.tableViewCanMoveRow) {
|
||||||
|
|||||||
@ -12,6 +12,20 @@
|
|||||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||||
#import <AsyncDisplayKit/ASAssert.h>
|
#import <AsyncDisplayKit/ASAssert.h>
|
||||||
|
|
||||||
|
// UIKit performs a class check for UIDataSourceModelAssociation protocol conformance rather than an instance check, so
|
||||||
|
// the implementation of conformsToProtocol: below never gets called. We need to declare the two as conforming to the protocol here, then
|
||||||
|
// we need to implement dummy methods to get rid of a compiler warning about not conforming to the protocol.
|
||||||
|
@interface ASTableViewProxy () <UIDataSourceModelAssociation>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASCollectionViewProxy () <UIDataSourceModelAssociation>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASDelegateProxy (UIDataSourceModelAssociationPrivate)
|
||||||
|
- (nullable NSString *)_modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view;
|
||||||
|
- (nullable NSIndexPath *)_indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view;
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation ASTableViewProxy
|
@implementation ASTableViewProxy
|
||||||
|
|
||||||
- (BOOL)interceptsSelector:(SEL)selector
|
- (BOOL)interceptsSelector:(SEL)selector
|
||||||
@ -54,10 +68,22 @@
|
|||||||
|
|
||||||
// used for batch fetching API
|
// used for batch fetching API
|
||||||
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:) ||
|
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:) ||
|
||||||
selector == @selector(scrollViewDidEndDecelerating:)
|
selector == @selector(scrollViewDidEndDecelerating:) ||
|
||||||
|
|
||||||
|
// UIDataSourceModelAssociation
|
||||||
|
selector == @selector(modelIdentifierForElementAtIndexPath:inView:) ||
|
||||||
|
selector == @selector(indexPathForElementWithModelIdentifier:inView:)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view {
|
||||||
|
return [self _modelIdentifierForElementAtIndexPath:indexPath inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
|
||||||
|
return [self _indexPathForElementWithModelIdentifier:identifier inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASCollectionViewProxy
|
@implementation ASCollectionViewProxy
|
||||||
@ -110,10 +136,22 @@
|
|||||||
|
|
||||||
// intercepted due to not being supported by ASCollectionView (prevent bugs caused by usage)
|
// intercepted due to not being supported by ASCollectionView (prevent bugs caused by usage)
|
||||||
selector == @selector(collectionView:canMoveItemAtIndexPath:) ||
|
selector == @selector(collectionView:canMoveItemAtIndexPath:) ||
|
||||||
selector == @selector(collectionView:moveItemAtIndexPath:toIndexPath:)
|
selector == @selector(collectionView:moveItemAtIndexPath:toIndexPath:) ||
|
||||||
|
|
||||||
|
// UIDataSourceModelAssociation
|
||||||
|
selector == @selector(modelIdentifierForElementAtIndexPath:inView:) ||
|
||||||
|
selector == @selector(indexPathForElementWithModelIdentifier:inView:)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view {
|
||||||
|
return [self _modelIdentifierForElementAtIndexPath:indexPath inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
|
||||||
|
return [self _indexPathForElementWithModelIdentifier:identifier inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASPagerNodeProxy
|
@implementation ASPagerNodeProxy
|
||||||
@ -220,4 +258,12 @@
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)_modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view {
|
||||||
|
return [(id)_interceptor modelIdentifierForElementAtIndexPath:indexPath inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSIndexPath *)_indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
|
||||||
|
return [(id)_interceptor indexPathForElementWithModelIdentifier:identifier inView:view];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user