照片 API 将 PHFetchResultChangeDetails 索引转换为 NSMutableOrderedSet
Photos API convert PHFetchResultChangeDetails indexes to NSMutableOrderedSet
我在 PHChange
事件发生后尝试更改数据源时遇到问题。我使用 NSMutableOrderedSet
作为我的数据源类型。当 PHChange
发生时,它可以返回三个可能的索引:removedIndexes
、insertedIndexes
和 changedIndexes
.
问题是我不确定如何在先前的数据源中反映这些变化。有人可以阐明我如何转换 PHChange
中给出的索引来更新我的 recentsCollectionDataSource
。我的 UICollectionView
使用 recentsCollectionDataSource
作为其数据源。
现在我认为唯一的方法是手动枚举和构建我自己的更改索引,而不是使用 PHFetchResultChangeDetails
索引。
如果能提供任何帮助,我将不胜感激。也欢迎任何关于制作我的数据源的替代方法的建议。
代码:
@property (nonatomic, strong) PHFetchResult *assetsFetchResult;
@property (nonatomic, strong) NSMutableOrderedSet *recentsCollectionDataSource;
- (void)setup
{
self.recentsCollectionDataSource = [[NSMutableOrderedSet alloc]init];
self.assetsFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum | PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
for (PHAssetCollection *sub in self.assetsFetchResult)
{
PHFetchResult *assetsInCollection = [PHAsset fetchAssetsInAssetCollection:sub options:nil];
for (PHAsset *asset in assetsInCollection)
{
[self.recentsCollectionDataSource addObject:asset];
}
}
if (self.recentsCollectionDataSource.count > 0)
{
NSArray *array = [self.recentsCollectionDataSource sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]];
self.recentsCollectionDataSource = [[NSMutableOrderedSet alloc]initWithArray:array];
}
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResult];
if (collectionChanges)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
self.assetsFetchResult = [collectionChanges fetchResultAfterChanges];
if (!collectionChanges.hasIncrementalChanges || collectionChanges.hasMoves)
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView reloadData];
});
}
else
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView performBatchUpdates:^
{
NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
NSIndexSet *changedIndexes = [collectionChanges changedIndexes];
// Need to update our old recentsCollectionDataSource
// somehow, otherwise we get a crash.
if (removedIndexes.count)
{
[self.recentsCollectionView deleteItemsAtIndexPaths:[removedIndexes indexPathsFromIndexesWithSection:0]];
}
if (insertedIndexes.count)
{
[self.recentsCollectionView insertItemsAtIndexPaths:[insertedIndexes indexPathsFromIndexesWithSection:0]];
}
if (changedIndexes.count)
{
[self.recentsCollectionView reloadItemsAtIndexPaths:[changedIndexes indexPathsFromIndexesWithSection:0]];
}
}completion:NULL];
});
}
});
}
}
@implementation NSIndexSet (Convenience)
- (NSArray *)indexPathsFromIndexesWithSection:(NSUInteger)section
{
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)
{
[indexPaths addObject:[NSIndexPath indexPathForItem:idx inSection:section]];
}];
return indexPaths;
}
@end
我似乎已经解决了(至少现在)。我分别构建了自己的删除、插入和更改索引,这不如内置 PHFetchResultChangeDetails
索引有效,但我不相信有另一种方法可以做到这一点。使用此代码在 iPhone 5 上浏览 2600 张照片大约需要 4 秒,所以还不错。
我注意到 PHFetchResultChangeDetails
可能有一个错误,它没有将最喜欢的更改放在更改详细信息中,所以如果你想保持视觉效果,不妨再次执行整个集合提取在你的 UI.
中保持一致
代码:
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResult];
if (collectionChanges)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
self.assetsFetchResult = [collectionChanges fetchResultAfterChanges];
NSMutableOrderedSet *newSet = [[NSMutableOrderedSet alloc]init];
for (PHAssetCollection *sub in self.assetsFetchResult)
{
PHFetchResult *assetsInCollection = [PHAsset fetchAssetsInAssetCollection:sub options:nil];
for (PHAsset *asset in assetsInCollection)
{
[newSet addObject:asset];
}
}
NSMutableIndexSet *removedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableIndexSet *insertedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableIndexSet *changedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableArray *objectsToInsert = [[NSMutableArray alloc]init];
if (newSet.count > 0)
{
NSArray *array = [newSet sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]];
newSet = [[NSMutableOrderedSet alloc]initWithArray:array];
for (id obj in newSet)
{
NSUInteger idx = [self.recentsCollectionDataSource indexOfObject:obj];
if (idx == NSNotFound)
{
[objectsToInsert addObject:obj];
[insertedIndexes addIndex:[newSet indexOfObject:obj]];
}
else
{
NSUInteger objIdx = [newSet indexOfObject:obj];
PHAsset *oldAssetToCompare = (PHAsset *)[self.recentsCollectionDataSource objectAtIndex:idx];
PHAsset *plausibleNewAssetToCompare = (PHAsset *)[newSet objectAtIndex:objIdx];
if (![oldAssetToCompare isEqual:plausibleNewAssetToCompare])
{
[changedIndexes addIndex:idx];
}
}
}
for (id obj in self.recentsCollectionDataSource)
{
NSUInteger idx = [newSet indexOfObject:obj];
if (idx == NSNotFound)
{
[removedIndexes addIndex:[self.recentsCollectionDataSource indexOfObject:obj]];
}
else
{
NSUInteger objIdx = [self.recentsCollectionDataSource indexOfObject:obj];
PHAsset *oldAssetToCompare = (PHAsset *)obj;
PHAsset *plausibleNewAssetToCompare = (PHAsset *)[newSet objectAtIndex:idx];
if (![oldAssetToCompare isEqual:plausibleNewAssetToCompare])
{
[changedIndexes addIndex:objIdx];
}
}
}
}
if (removedIndexes.count > 0)
{
[self.recentsCollectionDataSource removeObjectsAtIndexes:removedIndexes];
}
if (insertedIndexes.count > 0)
{
[self.recentsCollectionDataSource insertObjects:objectsToInsert atIndexes:insertedIndexes];
}
if (!collectionChanges.hasIncrementalChanges || collectionChanges.hasMoves)
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView reloadData];
});
}
else
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView performBatchUpdates:^
{
if (removedIndexes.count > 0)
{
[self.recentsCollectionView deleteItemsAtIndexPaths:[removedIndexes indexPathsFromIndexesWithSection:0]];
}
if (insertedIndexes.count > 0)
{
[self.recentsCollectionView insertItemsAtIndexPaths:[insertedIndexes indexPathsFromIndexesWithSection:0]];
}
if (changedIndexes.count > 0)
{
[self.recentsCollectionView reloadItemsAtIndexPaths:[changedIndexes indexPathsFromIndexesWithSection:0]];
}
}completion:NULL];
});
}
});
}
}
我在 PHChange
事件发生后尝试更改数据源时遇到问题。我使用 NSMutableOrderedSet
作为我的数据源类型。当 PHChange
发生时,它可以返回三个可能的索引:removedIndexes
、insertedIndexes
和 changedIndexes
.
问题是我不确定如何在先前的数据源中反映这些变化。有人可以阐明我如何转换 PHChange
中给出的索引来更新我的 recentsCollectionDataSource
。我的 UICollectionView
使用 recentsCollectionDataSource
作为其数据源。
现在我认为唯一的方法是手动枚举和构建我自己的更改索引,而不是使用 PHFetchResultChangeDetails
索引。
如果能提供任何帮助,我将不胜感激。也欢迎任何关于制作我的数据源的替代方法的建议。
代码:
@property (nonatomic, strong) PHFetchResult *assetsFetchResult;
@property (nonatomic, strong) NSMutableOrderedSet *recentsCollectionDataSource;
- (void)setup
{
self.recentsCollectionDataSource = [[NSMutableOrderedSet alloc]init];
self.assetsFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum | PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
for (PHAssetCollection *sub in self.assetsFetchResult)
{
PHFetchResult *assetsInCollection = [PHAsset fetchAssetsInAssetCollection:sub options:nil];
for (PHAsset *asset in assetsInCollection)
{
[self.recentsCollectionDataSource addObject:asset];
}
}
if (self.recentsCollectionDataSource.count > 0)
{
NSArray *array = [self.recentsCollectionDataSource sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]];
self.recentsCollectionDataSource = [[NSMutableOrderedSet alloc]initWithArray:array];
}
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResult];
if (collectionChanges)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
self.assetsFetchResult = [collectionChanges fetchResultAfterChanges];
if (!collectionChanges.hasIncrementalChanges || collectionChanges.hasMoves)
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView reloadData];
});
}
else
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView performBatchUpdates:^
{
NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
NSIndexSet *changedIndexes = [collectionChanges changedIndexes];
// Need to update our old recentsCollectionDataSource
// somehow, otherwise we get a crash.
if (removedIndexes.count)
{
[self.recentsCollectionView deleteItemsAtIndexPaths:[removedIndexes indexPathsFromIndexesWithSection:0]];
}
if (insertedIndexes.count)
{
[self.recentsCollectionView insertItemsAtIndexPaths:[insertedIndexes indexPathsFromIndexesWithSection:0]];
}
if (changedIndexes.count)
{
[self.recentsCollectionView reloadItemsAtIndexPaths:[changedIndexes indexPathsFromIndexesWithSection:0]];
}
}completion:NULL];
});
}
});
}
}
@implementation NSIndexSet (Convenience)
- (NSArray *)indexPathsFromIndexesWithSection:(NSUInteger)section
{
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)
{
[indexPaths addObject:[NSIndexPath indexPathForItem:idx inSection:section]];
}];
return indexPaths;
}
@end
我似乎已经解决了(至少现在)。我分别构建了自己的删除、插入和更改索引,这不如内置 PHFetchResultChangeDetails
索引有效,但我不相信有另一种方法可以做到这一点。使用此代码在 iPhone 5 上浏览 2600 张照片大约需要 4 秒,所以还不错。
我注意到 PHFetchResultChangeDetails
可能有一个错误,它没有将最喜欢的更改放在更改详细信息中,所以如果你想保持视觉效果,不妨再次执行整个集合提取在你的 UI.
代码:
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResult];
if (collectionChanges)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^
{
self.assetsFetchResult = [collectionChanges fetchResultAfterChanges];
NSMutableOrderedSet *newSet = [[NSMutableOrderedSet alloc]init];
for (PHAssetCollection *sub in self.assetsFetchResult)
{
PHFetchResult *assetsInCollection = [PHAsset fetchAssetsInAssetCollection:sub options:nil];
for (PHAsset *asset in assetsInCollection)
{
[newSet addObject:asset];
}
}
NSMutableIndexSet *removedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableIndexSet *insertedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableIndexSet *changedIndexes = [[NSMutableIndexSet alloc]init];
NSMutableArray *objectsToInsert = [[NSMutableArray alloc]init];
if (newSet.count > 0)
{
NSArray *array = [newSet sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]];
newSet = [[NSMutableOrderedSet alloc]initWithArray:array];
for (id obj in newSet)
{
NSUInteger idx = [self.recentsCollectionDataSource indexOfObject:obj];
if (idx == NSNotFound)
{
[objectsToInsert addObject:obj];
[insertedIndexes addIndex:[newSet indexOfObject:obj]];
}
else
{
NSUInteger objIdx = [newSet indexOfObject:obj];
PHAsset *oldAssetToCompare = (PHAsset *)[self.recentsCollectionDataSource objectAtIndex:idx];
PHAsset *plausibleNewAssetToCompare = (PHAsset *)[newSet objectAtIndex:objIdx];
if (![oldAssetToCompare isEqual:plausibleNewAssetToCompare])
{
[changedIndexes addIndex:idx];
}
}
}
for (id obj in self.recentsCollectionDataSource)
{
NSUInteger idx = [newSet indexOfObject:obj];
if (idx == NSNotFound)
{
[removedIndexes addIndex:[self.recentsCollectionDataSource indexOfObject:obj]];
}
else
{
NSUInteger objIdx = [self.recentsCollectionDataSource indexOfObject:obj];
PHAsset *oldAssetToCompare = (PHAsset *)obj;
PHAsset *plausibleNewAssetToCompare = (PHAsset *)[newSet objectAtIndex:idx];
if (![oldAssetToCompare isEqual:plausibleNewAssetToCompare])
{
[changedIndexes addIndex:objIdx];
}
}
}
}
if (removedIndexes.count > 0)
{
[self.recentsCollectionDataSource removeObjectsAtIndexes:removedIndexes];
}
if (insertedIndexes.count > 0)
{
[self.recentsCollectionDataSource insertObjects:objectsToInsert atIndexes:insertedIndexes];
}
if (!collectionChanges.hasIncrementalChanges || collectionChanges.hasMoves)
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView reloadData];
});
}
else
{
dispatch_async(dispatch_get_main_queue(),^
{
[self.recentsCollectionView performBatchUpdates:^
{
if (removedIndexes.count > 0)
{
[self.recentsCollectionView deleteItemsAtIndexPaths:[removedIndexes indexPathsFromIndexesWithSection:0]];
}
if (insertedIndexes.count > 0)
{
[self.recentsCollectionView insertItemsAtIndexPaths:[insertedIndexes indexPathsFromIndexesWithSection:0]];
}
if (changedIndexes.count > 0)
{
[self.recentsCollectionView reloadItemsAtIndexPaths:[changedIndexes indexPathsFromIndexesWithSection:0]];
}
}completion:NULL];
});
}
});
}
}