[英]-[UIDragSession loadObjectsOfClass:completion:] completionBlock not being called
我正在學習iOS11的新API拖放,但是我有一些疑問。 我有兩個collectionViews,它們共享相同類型的dataSource數組( DataEntity )。 一個用於拖動,另一個用於拖放。 這意味着我想將包含數據( DataEntity )的項目從一個collectionView拖到另一個。
然后我在[-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:]
。 我無法獲取在我的第一個collectionView中傳遞的數據( DataEntity ),因為未調用-[UIDragSession loadObjectsOfClass:completion:]
。 但是,如果我將其他類(例如UIImage.class或NSString.class)設置為參數loadObjectsOfClass:
則會調用完成塊,但是它不是兼容類,因此沒有返回對象。
源代碼
拖動collectionView
- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForBeginningDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath {
DataEntity* entity = self.entities[indexPath.row];
UIDragItem* item = [[UIDragItem alloc] initWithItemProvider:[[NSItemProvider alloc] initWithObject:entity]];
return @[item];
}
下降收集視圖
- (void)collectionView:(UICollectionView *)collectionView performDropWithCoordinator:(id<UICollectionViewDropCoordinator>)coordinator {
NSIndexPath* destinationIndexPath = coordinator.destinationIndexPath;
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView performBatchUpdates:^{
[coordinator.session loadObjectsOfClass:DataEntity.class completion:^(NSArray<__kindof id<NSItemProviderReading>> * _Nonnull objects) {
[objects enumerateObjectsUsingBlock:^(__kindof id<NSItemProviderReading> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self.mutableEntities insertObject:(DataEntity*)obj atIndex:destinationIndexPath.row];
[self.collectionView insertItemsAtIndexPaths:@[destinationIndexPath]];
}];
}];
} completion:nil];
});
}
- (BOOL)collectionView:(UICollectionView *)collectionView canHandleDropSession:(id<UIDropSession>)session {
BOOL test = [session canLoadObjectsOfClass:DataEntity.class]; // It's YES
return test;
}
數據實體
- (NSProgress *)loadDataWithTypeIdentifier:(NSString *)typeIdentifier forItemProviderCompletionHandler:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler {
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:self];
completionHandler(data, nil);
return nil;
}
+ (NSArray<NSString *> *)writableTypeIdentifiersForItemProvider {
NSString* identifier = NSStringFromClass(self.class);
return @[identifier];
}
+ (NSArray<NSString *> *)readableTypeIdentifiersForItemProvider {
NSString* identifier = NSStringFromClass(self.class);
return @[identifier];
}
+ (nullable instancetype)objectWithItemProviderData:(nonnull NSData *)data typeIdentifier:(nonnull NSString *)typeIdentifier error:(NSError * _Nullable __autoreleasing * _Nullable)outError {
DataEntity* entity = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return entity;
}
編輯
好的,我發現了一些東西。 首先,如果刪除dispatch_async(dispatch_get_main_queue())
,我將得到一個錯誤的無法識別的選擇器-[DataEntity encodeWithCoder:] 。 那是第二件事,我忘記使DataEntity符合NSCoding協議。
現在,新問題是,為什么我不能在dispatch_main_queue閉包中調用-[UIDragSession loadObjectsOfClass:completion:]
,否則將不會調用其完成塊?
所有這些都與異步代碼執行的基本原理有關。 在您的collectionView:performDropWithCoordinator:
實現中,此代碼是錯誤的:
dispatch_async(dispatch_get_main_queue(), ^{
[coordinator.session loadObjectsOfClass: // ...
當您調用dispatch_async
,您允許對collectionView:performDropWithCoordinator:
的調用返回—它結束了! 但是您要先進行此操作, 然后再繼續加載數據。 因此, 在您有機會提取數據之前 ,刪除操作立即結束,會話消失。 當我們進入loadObjectsOfClass
,就不再有數據了。 會話已經結束。
實際上,我打賭那時的session
為nil
。 發送到nil
對象的代碼什么也沒有做。 這就是為什么從不調用objectWithItemProviderData
和完成處理程序的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.