[英]-[UIDragSession loadObjectsOfClass:completion:] completionBlock not being called
I'm learning iOS11 new APIs Drag and Drop, but I have some questions. 我正在学习iOS11的新API拖放,但是我有一些疑问。 I have two collectionViews which share same type ( DataEntity ) of dataSource array.
我有两个collectionViews,它们共享相同类型的dataSource数组( DataEntity )。 One is for drag and the other is for drop.
一个用于拖动,另一个用于拖放。 That means I want to drag item which contains data ( DataEntity ) from one collectionView to another.
这意味着我想将包含数据( DataEntity )的项目从一个collectionView拖到另一个。
Then I have the question in [-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:]
. 然后我在
[-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:]
。 I can't fetch data ( DataEntity ) passed in my first collectionView because -[UIDragSession loadObjectsOfClass:completion:]
completionBlock is not being called. 我无法获取在我的第一个collectionView中传递的数据( DataEntity ),因为未调用
-[UIDragSession loadObjectsOfClass:completion:]
。 However, if I set other class (such as UIImage.class or NSString.class) to parameter loadObjectsOfClass:
completion block will get called, however it is not the compatible class so there's no return objects. 但是,如果我将其他类(例如UIImage.class或NSString.class)设置为参数
loadObjectsOfClass:
则会调用完成块,但是它不是兼容类,因此没有返回对象。
Source Code 源代码
Drag collectionView 拖动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];
}
Drop collectionView 下降收集视图
- (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;
}
Data entity 数据实体
- (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;
}
EDIT 编辑
Ok, I found something. 好的,我发现了一些东西。 First, if I remove the
dispatch_async(dispatch_get_main_queue())
, I will get an error unrecoginized selector -[DataEntity encodeWithCoder:] . 首先,如果删除
dispatch_async(dispatch_get_main_queue())
,我将得到一个错误的无法识别的选择器-[DataEntity encodeWithCoder:] 。 And that is the second thing, I forget to make DataEntity conform to NSCoding protocol. 那是第二件事,我忘记使DataEntity符合NSCoding协议。
Now the new question is, why I can't call -[UIDragSession loadObjectsOfClass:completion:]
in dispatch_main_queue closure, or its completion block won't be called? 现在,新问题是,为什么我不能在dispatch_main_queue闭包中调用
-[UIDragSession loadObjectsOfClass:completion:]
,否则将不会调用其完成块?
It all has to do with the basic principles of asynchronous code execution. 所有这些都与异步代码执行的基本原理有关。 In your implementation of
collectionView:performDropWithCoordinator:
, this code is wrong: 在您的
collectionView:performDropWithCoordinator:
实现中,此代码是错误的:
dispatch_async(dispatch_get_main_queue(), ^{
[coordinator.session loadObjectsOfClass: // ...
When you call dispatch_async
, you allow the call to collectionView:performDropWithCoordinator:
to return — it comes to an end! 当您调用
dispatch_async
,您允许对collectionView:performDropWithCoordinator:
的调用返回—它结束了! But you are doing that before you proceed to load the data. 但是您要先进行此操作, 然后再继续加载数据。 Therefore the drop ends immediately and the session disappears, before you have a chance to pick up the data.
因此, 在您有机会提取数据之前 ,删除操作立即结束,会话消失。 When we get to
loadObjectsOfClass
, there is no data any more; 当我们进入
loadObjectsOfClass
,就不再有数据了。 the session has already ended. 会话已经结束。
In fact, I bet the session
at that point is nil
. 实际上,我打赌那时的
session
为nil
。 And code sent to a nil
object does nothing; 发送到
nil
对象的代码什么也没有做。 that's why your objectWithItemProviderData
and the completion handler are never called. 这就是为什么从不调用
objectWithItemProviderData
和完成处理程序的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.